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