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 :
JSNBTut - Lesson 01 - introdução ao Spring
JSNBTut - Lesson 02 - introdução ao gerenciamento de dependências no SpringJSNBTut - 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.
Obrigatório:
JSNBTut - Lesson 05 - 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 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, 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 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 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 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 spring-3.2.0.M2 ou o mais atual, e localize-as na pasta libs conforme explicado no JSNBTut - Base
Clique no Run >> 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 e 2 Labels nessa tela arrastando da Pallete
![]() |
Figura 03 - Arraste os itens do Palette p/ dentro do formulario |
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 |
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 :
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 :
![]() |
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 |
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 |
// 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 jLabel1=ICONE + Total de usuarios e 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 |
![]() |
Figura 15 - Botão Preview Design |
você pode visualizar como a tela ficará em tempo de execução :
![]() |
Figura 16 - 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 .
Como o NB facilita isso ?
- Clique com o botão direito no botão Sair. Escolha Events>>Action>>actionPerformed , que significa quando o usuário clicar nesse botão.
![]() |
Figura 17 - Adicionando eventos |
![]() |
Figura 18 - actionPerformed , usaremos muito esse evento. |
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>> Project) e clique no botão Sair.
![]() |
Figura 19 - Executando o Projeto |
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 - 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) Teste o programa.
o resultado deve ser esse :
![]() |
Figura 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 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
- 1 Panel
- Painel com borda preta p/ nao deixar os elementos soltos na tela - jPanel1
-4 Labels
-- ícone usuario (opcional) jLbIcon
-- id jLbId
-- nome jLbNome
-- telefone jLbTelefone
- 3 campos texto
-- id - apenas leitura jTFId
-- nome jTFNome
-- telefone jTFTelefone
- 2 botões
-- cancelar 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 :
III) Vamos adicionar a função que carrega o contato para o formulário logo abaixo do contrutor 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 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 Contato privado nessa classe p/ conter o Contato Selecionado , encapsulamos e utilizamos Get/Set p/ acessá-lo;
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 :
- Verifique que o programa permite abrir várias janelas do mesmo registro. Será que isso é bom ??
- Essa implementação não foi nada elegante. Cadê o encapsulamento ?
![]() |
Figura 26 - Resposta 1 do passo 08 |
8) ainda : do jeito q está vamos implementar a Resposta 2 :
Resposta 2 do passo 08 :
I) Vamos adicionar a jTable um evento
![]() |
Figura 27 -Adicionando um evento de clique a nossa jTable |
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 ? 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 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 preciso e o botão edit lê o contatoAtivo.
Opa... 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 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.. Teste o programa.
![]() |
Figura 30 - Prevenindo o erro da função abreFrameEdit |
9) Vamos modificar um pouco como isso está escrito: , Refactor>>Encapsulate Fields
![]() |
Figura 31- Refatorando e Encapsulando : Após selecionar e aplicar , selecione as 5 que 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.. 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 .
![]() |
Figura 32 - Fechando apenas a janela filha |
II) Permitindo apenas uma janela de edição de Contato.
Vamos modificar a classe 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() na função abreFrameEdit 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.. 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 |
![]() |
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 springlesson06.dao.ContatoDAO
public void salvar(Contato C){ String sql=null; List<Object> params = new ArrayList<Object>(); 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 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 ContatoDAO `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 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, o resultado deve ser esse
![]() |
Figura 37 - Observe o Log, mas o registro foi salvo. |
R: Sim.
O sql é esse mesmo, lembre-se que no dao usamos t.update(sql, params.toArray()); e os valores estão no List<Object> 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 ContatoTableModel vamos implementar uma função que atualize essa grade :
public void atualizaLista(List<Contato> lista) { this.lista = lista; }
II) Na classe 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 frameEditaContato após salvar o Registro, chame a função da janela pai atualizaGrade e em seguida fechar , e gere a funcao getFlC() para acessar frame Pai
public frameListaContatos getFlC() { return flC; }E a função salvar ficou assim
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); }
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 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) : 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
public void apagar(Contato C) { JdbcTemplate t = getJdbcTemplate(); String sql = null; List<Object> params = new ArrayList<Object>(); sql = "DELETE FROM `springlessons`.`contato` " + " WHERE `id` = ? "; params.add(C.getId()); // System.out.println("SQL:" + sql); t.update(sql, params.toArray()); }
II) Na classe 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.
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 utilizando Swing e Spring
- Vimos como controlar uma Janela filha e chamar metodos e passar objetos entre elas
- Utilizamos nosso 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.
Nenhum comentário:
Postar um comentário