JAVA + Spring + Netbeans 7.2 - Mysql + Swing + CRUD Lesson 06
Autor: Mario Cezzare Angelicola Chiodi | Publicado: 2012-09-20T13:47:00-07:00




 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.config.clipboardSwf = 'http://alexgorbatchev.com/pub/sh/current/scripts/clipboard.swf';
SyntaxHighlighter.all();
 
Dando&nbsp;seqüência&nbsp;nos posts de JAVA + Spring

Requisitos :
- Netbeans 7.2
- spring-3.2.0.M2
- estar com o banco mysql springlessons, e a tabela contato criada. ver lição 4 ou 5

- Ter lido :


Posts Anteriores :&nbsp;

JSNBTut - Base&nbsp;&nbsp;que é uma preparação do ambiente para o desenvolvimento

Opcionais :&nbsp;

JSNBTut - Lesson 01&nbsp;- introdução ao Spring
JSNBTut - Lesson 02 -&nbsp;introdução ao gerenciamento de dependências no &nbsp;Spring

JSNBTut - Lesson 03&nbsp;- acessando banco de dados Mysql com beans e injeção de dependências
JSNBTut - Lesson 04&nbsp;-&nbsp;outro jeito rápido de utilizar o Spring e Mysql sem utilizar Arquivos XML.

Obrigatório:
JSNBTut - Lesson 05&nbsp;-&nbsp;comparação entre as implementações e introdução ao Swing. Jtable + 
DefaultTableModel e implementação de uma TableModel, analizando a 
aplicação com o Profile
, e apresentação do exemplo que usaremos nesta lição

Em vez de criar outro projeto, renomear , etc vou fornecer o projeto limpo dos testes e pronto p/ acompanhar a lição
- Alterei a classe Main p/ chamar &nbsp;o frameContato
- Refatorei o projeto p/ adequar ao tutorial
- Removi o que não estava sendo utilizado

Antes que alguém reclame de usar todas as libs do spring, &nbsp;nesse projeto incluí apenas as libs q estão sendo utilizadas (se estiver sobrando alguma, me avise ;) )



Figura 01- Inicio do projeto


Download do projeto NB
SpringLesson06-Base


Este é o 6º da série , o objetivo deste post é :
- Implementar um CRUD no exemplo
- Criar as telas adicionais

p/ economizar &nbsp;os screenshots, algumas coisas básicas como citar botão direito, nova classe etc, vou apenas apresentar a tela da criação da classe, os trechos importantes de código e no final da explicação o código inteiro, sem&nbsp; a parte gerada pelo NB p/ gerenciar o layout, e quando alterarmos uma propriedade de algo no Design mode, procurarei mostrar o q foi gerado no código quando importante para o entendimento &nbsp;do exemplo, porque no final da lição é fornecido o projeto completo que fazemos durante o tutorial.

O importante é ver o conceito e conseguir aplicar p/ seus exemplos, existem várias maneiras de resolver um problema, estou sugerindo um.


1) Ao abrir o Projeto, corrija as dependencias apontando as libs para a pasta onde vc baixou o spring&nbsp;spring-3.2.0.M2&nbsp;ou o mais atual, e localize-as na pasta libs conforme explicado no&nbsp;JSNBTut - Base&nbsp;

Clique no Run &gt;&gt; Project
o resultado deve ser parecido com esse :


Figura 02 - Teste o programa baixado ou renomeado


Se compilou e rodou, vamos adiante



2) abra o frameListaContato em modo Design e adicione 3 botões &nbsp;e 2 Labels nessa tela arrastando da Pallete



Figura 03 - Arraste os itens do Palette p/ dentro do formulario

A) Vamos acertar a Tela
I) Vamos definir o tamanho minimo da janela:
Clique duas vezes na linha cinza q envolve o formulário, vc deverá ver uma tela assim :


Figura 04 - Definindo as medidas da tela



II) Selecione o Frame e na aba properties faça 3 acertos :
a) Defina a propriedade title como Meus Contatos


Figura 05 - Defina o titulo do Frame


b) Defina a propriedade minimum size p/ ficar quase igual a size, p/ que o usuário não possa diminuir a tela, sumindo a grade e os botões


Figura 06 - Evitando redimensionamentos



B) Vamos acertar os botões :
Opcional : vou adicionar ícones aos botões:
Antes que alguém pergunte dos direitos.

The icons are free for personal use and also free for commercial use, but we require linking to our web site.
http://creativecommons.org/licenses/by-sa/3.0/
os ícones :&nbsp;

sair&nbsp;


usuario


adicionar/novo&nbsp;


remover&nbsp;


editar&nbsp;


Se vc optar por colocar os ícones, vamos criar um package p/ guardar as imagens :


Figura 07 - Criar um package p/ as imagens package name=springlessons06.images




Coloque as imagens dentro desse diretório :


Figura 08 - Coloque as imagens dentro da pasta imagens criada no NB


O NB já deve mostrar as imagens no Project Explorer :


Figura 09 - NB verifica alterações externas e mostra as imagens


I) No botão que tem o texto jButton1 , selecione esse botão e vamos acertar ele pela aba properties :
Defina as propriedades :
Text: Novo
tooTipText: Adicionar Contato
Se for adicionar a imagem, clique no icon, e selecione o ícone &nbsp;:


Figura 10 - Adicionando ícones ao programa, neste caso ao botão



II) Altere o nome da variável do botão para jBtNovo : isso vc pode fazer de 2 jeitos :


II a )- botão direito : Change Variable Name


Figura 11 - Alterando nome de variáveis



II b) - Botão direito, propriedades altere Variable Name

Figura 12 - Alterando nome de variáveis, essa caixa de propriedades pode ser acessada com o botao direito em qualquer objeto

o form deve ficar assim :


Figura 13 - Proposta visual do formulario com os botões

Veja o código gerado para entender a aplicação das propriedades na figura acima

// Variables declaration - do not modify
    private javax.swing.JButton jBtEditar;
    private javax.swing.JButton jBtNovo;
    private javax.swing.JButton jBtRemover;
    private javax.swing.JButton jBtSair;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;


e dentro da função initComponents


jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        jBtSair = new javax.swing.JButton();
        jBtNovo = new javax.swing.JButton();
        jBtEditar = new javax.swing.JButton();
        jBtRemover = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Meus Contatos");
        setMinimumSize(new java.awt.Dimension(638, 317));
        setSize(new java.awt.Dimension(638, 320));

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        jScrollPane1.setViewportView(jTable1);

        jBtSair.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/icon_sair.png"))); // NOI18N
        jBtSair.setText("Sair");

        jBtNovo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/user_add.png"))); // NOI18N
        jBtNovo.setText("Novo");
        jBtNovo.setToolTipText("Adicionar Contato");

        jBtEditar.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/user_edit.png"))); // NOI18N
        jBtEditar.setText("Editar");

        jBtRemover.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/user_delete.png"))); // NOI18N
        jBtRemover.setText("Remover");

        jLabel1.setText("jLabel1:");

        jLabel2.setText("jLabel2");


C) Vamos acertar os Labels, a idéia é informar o total de Registros : o label que contem o valor total iremos atualizar apenas esse texto , por isso 2 Labels;

Labels também podem conter imagens, então nossos Labels ficarão&nbsp;jLabel1=ICONE + Total de usuarios e&nbsp;jLabel2=0, que será renomeado p/ jLbTotal

Veja o código gerado :
   
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLbTotal;

    jLabel1 = new javax.swing.JLabel();
    jLbTotal = new javax.swing.JLabel();
    jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/user.png"))); // NOI18N
        jLabel1.setText("Total de Usuários");

        jLbTotal.setText("0");
        jLbTotal.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
E abaixo o resultado : 






Figura 14 - Edição do formulário em Modo Design

Clicando no botão Preview Design


Figura 15 &nbsp;- Botão Preview Design&nbsp;


você pode visualizar como a tela ficará em tempo de execução :


Figura 16 -&nbsp;Clique Preview Design


Conseguiu deixar o formulário com essa cara ?
Vamos adiante...

3) Vamos adicionar funcionalidade aos botões, mas antes é necessário saber que os eventos serão tratados utilizando java.awt.event.ActionEvent.
Então criamos funções normalmente chamadas de nomeObjetoActionPerformed&nbsp;.

Como o NB facilita isso ?
- Clique com o botão direito no botão Sair. Escolha Events&gt;&gt;Action&gt;&gt;actionPerformed , que significa quando o usuário clicar nesse botão.



Figura 17 - Adicionando eventos




Figura 18 - actionPerformed , usaremos muito esse evento.

2 - Clique duas vezes nesse botão que o NB já criará o código necessário e colocamos o que precisamos dentro dessa função :

    private void jBtSairActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:
    }


que encerraremos o programa

    private void jBtSairActionPerformed(java.awt.event.ActionEvent evt) {
        System.out.println("Encerrando programa ");
        System.exit(0);
    }


veja o que o NB gerou p/ esse evento :


       jBtSair.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/icon_sair.png"))); // NOI18N
        jBtSair.setText("Sair");
        jBtSair.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jBtSairActionPerformed(evt);
            }
        });




3) Teste o programa (isso quer dizer , aperte o F6 do teclado ou menu Run&gt;&gt; Project) e clique no botão Sair.


Figura 19 - Executando o Projeto&nbsp;

o log do NB deve mostrar algo assim :

Sep 21, 2012 1:37:33 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5815338: startup date [Fri Sep 21 13:37:33 BRT 2012]; root of context hierarchy
Sep 21, 2012 1:37:33 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans-definitions.xml]
Sep 21, 2012 1:37:34 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@36c8570c: defining beans [dataSource,jdbcTemplate,ContatoDao]; root of factory hierarchy
Sep 21, 2012 1:37:34 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Sep 21, 2012 1:37:36 PM org.springframework.jdbc.datasource.SingleConnectionDataSource initConnection
INFO: Established shared JDBC Connection: com.mysql.jdbc.JDBC4Connection@316d3536
Encerrando programa 
BUILD SUCCESSFUL (total time: 33 seconds)


4) Vamos acertar o label &nbsp;- na função carregaTabela que está em nossa Classe Main vamos adicionar a linha q atualiza o campo jlbTotal ficando assim :

    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);
        jLbTotal.setText(tableModel.getRowCount()+"");
    }


5)&nbsp;Teste o programa.
o resultado deve ser esse :


Figura&nbsp;21 - Execução do programa, repare o total de usuários : 2


6) Para editar e criar um novo Contato , vamos criar outro Frame de nome frameEditaContato no package springlesson06.view.contato:

I) Crie o JFrame


Figura&nbsp;22 - Adicionando outro JFrame




Figura 23 - nomeie o JFrame frameEditaContato, usaremos p/ Insert e Update


II) Adicionando os campos
e nesse formulário precisamos criar campos que atendam os campos da tabela no banco:
o que precisamos adicionar nesse form ?
- Adicionar&nbsp;

- 1 Panel&nbsp;
- Painel com borda preta p/ nao deixar os elementos soltos na tela -&nbsp;jPanel1

-4 Labels
-- ícone usuario (opcional) jLbIcon
-- id &nbsp;jLbId
-- nome&nbsp;jLbNome
-- telefone &nbsp;jLbTelefone
- 3 campos texto

-- id - apenas leitura&nbsp;jTFId
-- nome &nbsp;jTFNome
-- telefone&nbsp;jTFTelefone


- 2 botões
-- salvar &nbsp;jBtSalvar
-- cancelar&nbsp;jBtCancelar




Figura 24 - Após arrastar os elementos p/ o Form


Após customizado :



Figura 25 - Após editar as propriedades dos elementos do Form e o modo Preview


Vamos ver o que o NB fez com o código lá dentro da função initComponents:

private javax.swing.JButton jBtCancelar;
    private javax.swing.JButton jBtSalvar;
    private javax.swing.JLabel jLbIcon;
    private javax.swing.JLabel jLbId;
    private javax.swing.JLabel jLbNome;
    private javax.swing.JLabel jLbTelefone;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JTextField jTFId;
    private javax.swing.JTextField jTFNome;
    private javax.swing.JTextField jTFTelefone;

        jPanel1 = new javax.swing.JPanel();
        jTFTelefone = new javax.swing.JTextField();
        jLbTelefone = new javax.swing.JLabel();
        jLbNome = new javax.swing.JLabel();
        jTFNome = new javax.swing.JTextField();
        jTFId = new javax.swing.JTextField();
        jLbId = new javax.swing.JLabel();
        jBtSalvar = new javax.swing.JButton();
        jBtCancelar = new javax.swing.JButton();
        jLbIcon = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Contato");
        setResizable(false);

        jPanel1.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));

        jLbTelefone.setText("TELEFONE");

        jLbNome.setText("NOME");
        jTFId.setEnabled(false);
        jLbId.setText("ID");

        jBtSalvar.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/icon_save.png"))); // NOI18N
        jBtSalvar.setText("Salvar");

        jBtCancelar.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/icon_cancel_menor.png"))); // NOI18N
        jBtCancelar.setText("Cancelar");

        jLbIcon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/springlesson06/images/user.png"))); // NOI18N


e as novas imagens :

cancelar&nbsp;


salvar&nbsp;

III) Vamos adicionar a função que carrega o contato para o formulário logo abaixo &nbsp;do contrutor&nbsp;frameEditaContato:

  
public frameEditaContato() {
        initComponents();
}
public void carregaContato(Contato C){
        jTFId.setText(C.getId()+"");
        jTFNome.setText(C.getNome());
        jTFTelefone.setText(C.getTelefone());
    }




7) Agora precisaremos alterar nosso ContatoTableModel p/ retornar um object Contato para passar p/ o carregaContato que acabamos de fazer então em nossa classe&nbsp;springlesson06.model.ContatoTableModel vamos adicionar a seguinte função :


  
  public Contato getObjectAtRow(int row){
        return lista.get(row); 
    }
    


8) Vamos fazer o botão editar da lista de contatos abrir o frame frameEditaContato passando o objeto Contato :
Clique duas vezes no botão jBtEditar


 
private void jBtEditarActionPerformed(java.awt.event.ActionEvent evt) {
        Contato C = tableModel //???????
    }



e agora ?? não consigo acessar o objeto criado na função carregaTabela. Como resolve isso ?

R1 : Criamos um objeto ContatoTableModel privado nessa classe p/ conter o tableModel , encapsulamos e utilizamos Get/Set p/ acessá-lo;


R2 : Criamos um objeto&nbsp;Contato &nbsp;privado nessa classe p/ conter o Contato Selecionado , encapsulamos e utilizamos Get/Set p/ acessá-lo;


R3: etc...&nbsp;

Pensanndo.. o que é melhor ? o que precisaremos acessar ?
Vamos pensar na Resposta 1. alguns trechos do código modificado :
Resposta 1 do passo 08
//declaracao
public class frameListaContatos extends javax.swing.JFrame {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-definitions.xml");
        ContatoDAO dao = (ContatoDAO) ctx.getBean("contatoDao");
        ContatoTableModel tableModel = new ContatoTableModel(dao.listar());
//construtor
public frameListaContatos() {
        initComponents();
        carregaTabela();
    }
    private void carregaTabela(){
        jTable1.setModel(this.tableModel);
        jLbTotal.setText(this.tableModel.getRowCount()+"");
    }
//botao sair
 private void jBtSairActionPerformed(java.awt.event.ActionEvent evt) {
        System.out.println("Encerrando programa ");
        System.exit(0);
    }
//botao editar
    private void jBtEditarActionPerformed(java.awt.event.ActionEvent evt) {
        Contato C = this.tableModel.getObjectAtRow(jTable1.getSelectedRow());
        frameEditaContato fec = new frameEditaContato();
        fec.carregaContato(C);
        fec.setVisible(true);
    }



8) ainda : R1 Teste o programa.

Ao carregar o form com o titulo Meus Contatos , Selecione algum contato e clique no botao jBtEditar.

Funcionou ?? Boa , então :&nbsp;

- Verifique que o programa permite abrir várias janelas do mesmo registro.&nbsp;Será que isso é bom ??&nbsp;

- Essa implementação não foi nada elegante. Cadê o encapsulamento ?&nbsp;




Figura 26 - Resposta 1 do passo 08


8) ainda : do jeito q está vamos implementar a Resposta 2 :
Resposta 2 do passo 08 :&nbsp;
I) Vamos adicionar a jTable um evento


Figura 27 -Adicionando um evento de clique a nossa jTable

e o o código modificado

public class frameListaContatos extends javax.swing.JFrame {

    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-definitions.xml");
    ContatoDAO dao = (ContatoDAO) ctx.getBean("contatoDao");
    ContatoTableModel tableModel = new ContatoTableModel(dao.listar());
    Contato contatoAtivo;

    /**
     * Creates new form frameListaContatos
     */
    public frameListaContatos() {
        initComponents();
        carregaTabela();
    }

    private void carregaTabela() {
        jTable1.setModel(this.tableModel);
        jLbTotal.setText(this.tableModel.getRowCount() + "");
    }

    private void carregaContato() {
        Contato C = this.tableModel.getObjectAtRow(jTable1.getSelectedRow());
        this.contatoAtivo = C;
        System.out.println("Contato Ativo na memória: " + C.getNome());
    }

    private void abreFrameEdit(Contato C) {
        frameEditaContato fec = new frameEditaContato();
        fec.carregaContato(C);
        fec.setVisible(true);
    }

    private void sair() {
        System.out.println("Encerrando programa ");
        System.exit(0);
    }

/// NB CODE
 private void jBtSairActionPerformed(java.awt.event.ActionEvent evt) {
        sair();
    }

    private void jBtEditarActionPerformed(java.awt.event.ActionEvent evt) {
        abreFrameEdit(this.contatoAtivo);
    }

    private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {
        carregaContato();
    }
    public static void main(String args[]) {...}
 // Variables declaration - do not modify
    private javax.swing.JButton jBtEditar;
    private javax.swing.JButton jBtNovo;
    private javax.swing.JButton jBtRemover;
    private javax.swing.JButton jBtSair;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLbTotal;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    // End of variables declaration


E o que fizemos aqui ?&nbsp;Teste o programa.


Figura 28 - Teste do Programa , veja o Log do seu NB


Quando o usuário selecionar alguma linha , será executado a função &nbsp;jTable1MouseClicked tratado peloListener criado em 

   jTable1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTable1MouseClicked(evt);
            }
        });


E com isso colocamos o objeto Contato na memória e podemos utilizá-lo para mais coisa se for&nbsp;preciso e &nbsp;o botão edit lê o contatoAtivo.

Opa... &nbsp;e se clicar direto no botao editar, sem selecionar uma linha ??


Figura 29 - Erro causado por clicar no botao editar sem selecionar um contato, perceba o java.lang.NullPointerException


Yes... Erro
Em vez de colocar isso dentro de um Try/catch , nesse caso prefiro evitar que o erro aconteça da seguinte maneira :

II) Vamos modificar a função&nbsp;abreFrameEdit que precisa de um contato válido


      private void abreFrameEdit(Contato C) {
        if (C==null){
            JOptionPane.showMessageDialog(null,"Selecione um Contato");
        }else {
        frameEditaContato fec = new frameEditaContato();
        fec.carregaContato(C);
        fec.setVisible(true);
        }
    }

e..&nbsp;Teste o programa.


Figura 30 - Prevenindo o erro da função&nbsp;abreFrameEdit



9) Vamos modificar um pouco como isso está escrito: , Refactor&gt;&gt;Encapsulate Fields


Figura 31- Refatorando e Encapsulando :&nbsp;Após selecionar e aplicar , selecione as 5 que &nbsp;utilizei


public final class frameListaContatos extends javax.swing.JFrame {

    private ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-definitions.xml");
    private ContatoDAO dao = (ContatoDAO) ctx.getBean("contatoDao");
    private ContatoTableModel tableModel = new ContatoTableModel(dao.listar());
    private Contato contatoAtivo;

     public frameListaContatos() {
        initComponents();
        carregaTabela();
    }
 private void jBtSairActionPerformed(java.awt.event.ActionEvent evt) {
        sair();
    }

    private void jBtEditarActionPerformed(java.awt.event.ActionEvent evt) {
        abreFrameEdit(this.getContatoAtivo());
    }

    private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {
        carregaContato();
    }
//NB CODE
// End of variables declaration

    public ApplicationContext getCtx() {
        return ctx;
    }

    public ContatoDAO getDao() {
        return dao;
    }

    public ContatoTableModel getTableModel() {
        return tableModel;
    }

    public Contato getContatoAtivo() {
        return contatoAtivo;
    }

    public void setContatoAtivo(Contato contatoAtivo) {
        this.contatoAtivo = contatoAtivo;
    }

    private void carregaTabela() {
        jTable1.setModel(this.getTableModel());
        jLbTotal.setText(this.getTableModel().getRowCount() + "");
    }

    private void carregaContato() {
        Contato C = this.getTableModel().getObjectAtRow(jTable1.getSelectedRow());
        this.setContatoAtivo(C);
        System.out.println("Contato Ativo na memória: " + C.getNome());
    }

    private void abreFrameEdit(Contato C) {
        if (C == null) {
            JOptionPane.showMessageDialog(null, "Selecione um Contato");
        } else {
            frameEditaContato fec = new frameEditaContato();
            fec.carregaContato(C);
            fec.setVisible(true);
        }
    }

    private void sair() {
        System.out.println("Encerrando programa ");
        System.exit(0);
    }


e..&nbsp;Teste o programa.


10) O lance de abrir várias janelas:
Não sou muito fã disso, pois sujeito o usuário abrir várias janelas sem perceber e fazer uma bagunça com os dados.

I) mais uma modificação : se fechar a janela de edição fecha o programa, e não apenas a janela.
Para resolver isso abra o frameEditaContato , selecione o frame e nas propriedades altere a propriedade defaultCloseOperation para DISPOSE .&nbsp;


Figura 32 - Fechando apenas a janela filha



II) Permitindo apenas uma janela de edição de Contato.
Vamos modificar a classe&nbsp;frameEditaContato p/ receber como construtor o frame pai.

public class frameEditaContato extends javax.swing.JFrame {

    /**
     * Creates new form frameEditaContato
     */
    frameListaContatos flC;
   
//    public frameEditaContato() {
//        initComponents();
//    }
    
    //novo construtor
    public frameEditaContato(frameListaContatos flC) {
        initComponents();
        this.flC = flC;
    }
    // métoodo obrigatório
    private frameEditaContato() {
//        throw new UnsupportedOperationException("Not yet implemented");
    }
    
    public void carregaContato(Contato C){
        jTFId.setText(C.getId()+"");
        jTFNome.setText(C.getNome());
        jTFTelefone.setText(C.getTelefone());
    }
//... etc

E para chamar esse frame em nossa Lista criamos uma variável de classse privada do tipo frameEditaContato chamada janelaEdicao e passamos um novo objeto passando o construtor sem parâmetros() &nbsp;na função&nbsp;abreFrameEdit&nbsp;q recebe o contato Ativo, se estiver carregado.
modificação :

public final class frameListaContatos extends javax.swing.JFrame {

    private ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-definitions.xml");
    private ContatoDAO dao = (ContatoDAO) ctx.getBean("contatoDao");
    private ContatoTableModel tableModel = new ContatoTableModel(dao.listar());
    private Contato contatoAtivo;
    private frameEditaContato janelaEdicao;
  
     public frameEditaContato getJanelaEdicao() {
        return janelaEdicao;
    }

    public void setJanelaEdicao(frameEditaContato janelaEdicao) {
        this.janelaEdicao = janelaEdicao;
    }

    /**
     * Creates new form frameListaContatos
     */
    public frameListaContatos() {
        initComponents();
        carregaTabela();
        setJanelaEdicao(new frameEditaContato(this));
    }

// e na função usa o objeto janelaEdicao pelo método getJanelaEdicao();
  private void abreFrameEdit(Contato C) {
        if (C == null) {
            JOptionPane.showMessageDialog(null, "Selecione um Contato");
        } else {
            frameEditaContato fec = getJanelaEdicao();
            fec.carregaContato(C);
            fec.setVisible(true);
        }
    }
}


e..&nbsp;Teste o programa.

OBS, Como estamos utilizando um objeto Contato, observe em seu Mysql , que podemos abrir várias janelas sem aumentar as conexões :


Figura 33 - Usando o MysqlWorkBench para monitorar as conexões&nbsp;

OBS : Pelo MysqlWORKBench é possível realizar diversas tarefas administrativas, aproveite a conexão criada e a utilize na seção Server Administration



Figura 34 - Opção Server Administration do MWB, vale a pena conferir



11) Salvando os registros (UPDATE) : CRUD

I) Vamos adicionar uma função salvar em nosso contatoDAO&nbsp;springlesson06.dao.ContatoDAO

public void salvar(Contato C){
        String sql=null;
        List&lt;Object&gt; params = new ArrayList&lt;Object&gt;();
        
        if ( C.getId()==0 ){
        // novo contato  
            sql="INSERT INTO `springlessons`.`contato`"
            + "(`id`,`nome`,`telefone`) VALUES (?,?,?)";
            params.add(0);
            params.add(C.getNome());
            params.add(C.getTelefone());
      
        }else {
        //atualiza existente
            sql="UPDATE `springlessons`.`contato` "
            + " SET `nome` = ?,"
            + " `telefone` = ?"
            + " WHERE `id` = ? ";
            params.add(C.getNome());
            params.add(C.getTelefone());
            params.add(C.getId());
        }
// se der erros descomente abaixo e veja se o contato chegou aqui, mais p/ frente veremos q isso é uma pegadinha 
//System.out.println("SQL:" + sql);
        t.update(sql, params.toArray());
    }



II) Vamos modificar o construtor do objeto Contato inicializando ele com id=0, devido a verificação no método salvar, abra a classe Contato&nbsp;springlesson06.model.Contato
dica : com a classe aberta aperte ctrl + espaço e escolha a 1ª opção generate



Figura 35 - Classe Contato, utilizando os atalhos do NB p/ gerar as funções


ficando assim :

package springlesson06.model;

public class Contato {

    private int id;
    private String nome;
    private String telefone;

    public Contato() {
        this.id = 0;
    }


   public Contato(int id, String nome, String telefone) {
        this.id = id;
        this.nome = nome;
        this.telefone = telefone;
    }
    public int getId() {
        return id;
    }

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

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

III) no frameEditaContato que não conhece o DAO, precisamos informar onde serão salvos os dados.
Para isso , vamos adicionar um objeto dao do tipo&nbsp;ContatoDAO&nbsp;`a classe, e adicionar um objeto desse tipo no construtor do Frame springlesson06.view.contato.frameEditaContato:


package springlesson06.view.contato;

import springlesson06.dao.ContatoDAO;
import springlesson06.model.Contato;

public class frameEditaContato extends javax.swing.JFrame {

    frameListaContatos flC;
    ContatoDAO dao ;
    
    //novo construtor
    public frameEditaContato(frameListaContatos flC,ContatoDAO daoInformed) {
        initComponents();
        this.flC = flC;
        this.dao = daoInformed;
    }
    // métoodo obrigatório usado em Run
    private frameEditaContato() { }
    
    public void carregaContato(Contato C){
        jTFId.setText(C.getId()+"");
        jTFNome.setText(C.getNome());
        jTFTelefone.setText(C.getTelefone());
    }
//NB CODE
 public static void main(String args[]) {
        
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new frameEditaContato().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private javax.swing.JButton jBtCancelar;
    private javax.swing.JButton jBtSalvar;
    private javax.swing.JLabel jLbIcon;
    private javax.swing.JLabel jLbId;
    private javax.swing.JLabel jLbNome;
    private javax.swing.JLabel jLbTelefone;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JTextField jTFId;
    private javax.swing.JTextField jTFNome;
    private javax.swing.JTextField jTFTelefone;
    // End of variables declaration

  
}

Tirando a parte do NB se o seu codigo estiver como o acima, com dao criado , vamos fazer salvar os dados

IV) Agora em modo Design clique duas vezes no botão salvar : vamos editar a função&nbsp;jBtSalvarActionPerformed

Dica : dentro da função escreva salvarContato() (que ainda não existe) e veja a sugestão do NB, aceite;


Figura 36 - Mais uma vez utilize o NB p/ gerar a função. Pessoalmente acho q usar esses recursos diminuem a margem de erros e nomes que não sejam evidentes


Antes de mostrar a função salvarContato, algumas explicações :
Acho mais fácil criar + uma variavel do tipo Contato e encapsular as que ja temos, e criar um novo Contato no construtor do frame, que já terá um id=0 e não precisamos ficar convertendo o valor do id p/ String a todo momento:, resumindo modifiquei a classe , segue ela abaixo

package springlesson06.view.contato;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import springlesson06.dao.ContatoDAO;
import springlesson06.model.Contato;

public class frameEditaContato extends javax.swing.JFrame {

    private frameListaContatos flC;
    private ContatoDAO dao;
    private Contato contato;

    //novo construtor
    public frameEditaContato(frameListaContatos flC, ContatoDAO daoInformed) {
        initComponents();
        this.flC = flC;
        this.dao = daoInformed;
        this.contato = new Contato(); // que já possui um id=0
    }
    // método obrigatório

    private frameEditaContato() {
    }

    public void carregaContato(Contato C) {
        this.setContato(C);
        jTFId.setText(C.getId() + "");
        jTFNome.setText(C.getNome());
        jTFTelefone.setText(C.getTelefone());
    }

    private void salvarContato() {

        Contato C = new Contato();
        //Solução 1 : validação manual 
        String preMessage = "Verifique os seguintes erros:\n";
        String message = "";

        if ("".equals(jTFNome.getText())) {
            message += "- Nome deve ser preenchido \n";
        }
       
        if (message.length() == 0) {
            if ("".equals(jTFId.getText())) {
                C.setId(0);
            } else {

                C.setId(Integer.parseInt(jTFId.getText()));
                C.setNome(jTFNome.getText());
                C.setTelefone(jTFTelefone.getText());
            }
            this.contato = C;
            try {
                this.getDao().salvar(this.getContato());
                System.out.println("Salvando Contato:" + C.getNome());
                this.getFlC().atualizaGrade();
                this.dispose();
            } catch (java.lang.NullPointerException npe) {
                System.out.println("Erro ao Salvar o  Contato.");
                Logger.getLogger(frameEditaContato.class.getName()).log(Level.SEVERE, null, npe);
            }
        } else {
            JOptionPane.showMessageDialog(null, preMessage + message);
        }
    }
//NB CODE
 public static void main(String args[]) {
        
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new frameEditaContato().setVisible(true);
            }
        });
    }

    private void jBtSalvarActionPerformed(java.awt.event.ActionEvent evt) {
        salvarContato();
    }
    public static void main(String args[]) {
       

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new frameEditaContato().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private javax.swing.JButton jBtCancelar;
    private javax.swing.JButton jBtSalvar;
    private javax.swing.JLabel jLbIcon;
    private javax.swing.JLabel jLbId;
    private javax.swing.JLabel jLbNome;
    private javax.swing.JLabel jLbTelefone;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JTextField jTFId;
    private javax.swing.JTextField jTFNome;
    private javax.swing.JTextField jTFTelefone;
    // End of variables declaration
public ContatoDAO getDao() {
        return dao;
    }

    public Contato getContato() {
        return contato;
    }

    public void setContato(Contato contato) {
        this.contato = contato;
    }
}

Após as alterações , 


12) Teste o programa.
Selecione algum registro , clique em editar , altere o nome e clique em salvar, &nbsp;o resultado deve ser esse


Figura 37 - Observe o Log, mas o registro foi salvo.&nbsp;

hummm , o que aconteceu com o sql ?? será que atualizou ?
R: Sim.
O sql é esse mesmo, lembre-se que no dao usamos&nbsp;t.update(sql, params.toArray()); e os valores estão&nbsp;no&nbsp;List&lt;Object&gt; params.
Feche o programa e abra ele de novo que mostrará o registro atualizado.

13) Fechando a tela de edição e atualizando a Grade
I) Na classe&nbsp;ContatoTableModel vamos implementar uma função que atualize essa grade :

  
public void atualizaLista(List&lt;Contato&gt; lista) {
    this.lista = lista;
    }



II) Na classe&nbsp;frameListaContatos vamos criar uma função que chama essa q atualiza a lista p/ poder chamar da janela de edição após salvar o Registro

   public void atualizaGrade(){
        this.getTableModel().atualizaLista(this.getDao().listar());
        jTable1.updateUI();
        
    }



III) Na classe&nbsp;frameEditaContato após salvar o Registro, chame a função da janela pai atualizaGrade e em seguida fechar , e gere a funcao&nbsp;getFlC() para acessar frame Pai
 
     public frameListaContatos getFlC() {
        return flC;
    }


&nbsp;E a função salvar ficou assim&nbsp;


 
private void salvarContato() {

        Contato C = new Contato();
        //Solução 1 : validação manual 
        String preMessage = "Verifique os seguintes erros:\n";
        String message = "";

        if (!"".equals(jTFNome.getText())) {
            message += "- Nome deve ser preenchido \n";
        }

        if (message.length() &gt; 0) {
            if ("".equals(jTFId.getText())) {
                C.setId(0);
            } else {

                C.setId(Integer.parseInt(jTFId.getText()));
                C.setNome(jTFNome.getText());
                C.setTelefone(jTFTelefone.getText());
            }
            this.contato = C;
            try {
                this.getDao().salvar(this.getContato());
                System.out.println("Salvando Contato:" + C.getNome());
                this.getFlC().atualizaGrade();
                this.dispose();
            } catch (java.lang.NullPointerException npe) {
                System.out.println("Erro ao Salvar o  Contato.");
                Logger.getLogger(frameEditaContato.class.getName()).log(Level.SEVERE, null, npe);
            }
        } else {
            JOptionPane.showMessageDialog(null, preMessage + message);
        }




13 )Teste o programa.

I) Edite um contato e salve veja se está tudo funcionando, após salvar a tela de edição deve fechar e a Grade de baixo atualizar. :
Meu Output :

run:
Sep 21, 2012 8:37:06 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@48ff2413: startup date [Fri Sep 21 20:37:06 BRT 2012]; root of context hierarchy
Sep 21, 2012 8:37:06 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans-definitions.xml]
Sep 21, 2012 8:37:07 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@469a9b65: defining beans [dataSource,jdbcTemplate,ContatoDao]; root of factory hierarchy
Sep 21, 2012 8:37:07 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Sep 21, 2012 8:37:08 PM org.springframework.jdbc.datasource.SingleConnectionDataSource initConnection
INFO: Established shared JDBC Connection: com.mysql.jdbc.JDBC4Connection@52b57e9a
Contato Ativo na memória: Cliente 2 renomeado
SQL:UPDATE `springlessons`.`contato`  SET `nome` = ?, `telefone` = ? WHERE `id` = ? 
Salvando Contato:Cliente 2 renomeado de novo
Encerrando programa 
BUILD SUCCESSFUL (total time: 1 minute 59 seconds)

14) Salvando novos registros : esse ficou fácil

I) Na classe&nbsp;frameListaContatos vamos criar uma função que chama o cadastro
Clique duas vezes no botao novo :


    
private void jBtNovoActionPerformed(java.awt.event.ActionEvent evt) {
        abreFrameEdit(new Contato());
    }


II) E mande atualizar o label Total apos as inserções / atualizações: 

public void atualizaGrade(){
        this.getTableModel().atualizaLista(this.getDao().listar());
        jTable1.updateUI();
        jLbTotal.setText(this.getTableModel().getRowCount() + "");
        
    }



Teste o programa. Veja se o label total esta atualizando após inserir registros.

15) Removendo registros :(DELETE) :&nbsp;CRUD

I) Vamos fazer função delete no contatoDAO e a ação do botão Remover
springlesson06.dao.ContatoDAO , adicione a função abaixo

   &nbsp;
public void apagar(Contato C) {
        JdbcTemplate t = getJdbcTemplate();
        String sql = null;
        List&lt;Object&gt; params = new ArrayList&lt;Object&gt;();
        sql = "DELETE FROM `springlessons`.`contato` "
                + " WHERE `id` = ? ";
        params.add(C.getId());
//        System.out.println("SQL:" + sql);
        t.update(sql, params.toArray());
    }



II) Na classe&nbsp;frameListaContatos vamos criar uma função que chama o cadastro
Clique duas vezes no botao remover :

     private void jBtRemoverActionPerformed(java.awt.event.ActionEvent evt) {
        removeContato();
    }

e escreva a função removeContato, observe que estou utilizando o objeto Logger daqui p/ frente : (p/ mostrar os erros, o NB usa ele por default)


  
  private void removeContato(Contato C) {
        if (C != null) {
            int apaga = JOptionPane.showConfirmDialog(null, "Deseja Apagar o contato  " + C.getNome(),
                    "Sistema informa:", JOptionPane.YES_NO_OPTION);
            if (apaga == JOptionPane.YES_OPTION) {

                try {
                    System.out.println("Removendo contato do banco: " + C.getNome());
                    this.getDao().apagar(C);
                    System.out.println("Removendo contato Ativo da memória: " + C.getNome());
                    setContatoAtivo(null);
                    atualizaGrade();
                } catch (Exception ex) {
                    Logger.getLogger(frameListaContatos.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } else {
            JOptionPane.showMessageDialog(null, "Selecione um Contato");
        }
    }


16) Teste o programa.&nbsp;
o resultado agora ao clicar no remover deve ser uma confirmação, escolha sim e remova o registro.


Figura 38 - Confirmação da execução através de uma Caixa de Diálogo





Figura 39 - Agora o contato é removido se escolhido a opção Sim, e a grade atualizada.





Download do projeto NB
SpringLesson06-v1.zip

Corrigido a função de salvar Contato q tinha um bug :
SpringLesson06-V2.zip


Experimente executar o Profile e compare os resultados.

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

Resumo : o que foi feito ?
- Implementamos um CRUD em Java &nbsp; utilizando&nbsp;Swing e&nbsp;&nbsp;Spring
- Vimos como controlar uma Janela filha e chamar metodos &nbsp;e passar objetos entre elas
- Utilizamos nosso&nbsp;ContatoTableModel p/ controlar os dados da Grade
- Vimos um pouco de como o NB gera os códigos (que são protegidos no ambiente de código, mas todas as suas propriedades podem ser alterados pelo GUI)
- Vimos mais faciliddes do NB



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