Permite que você use objetos de data, sem ter que se preocupar com formato do banco de dados. Isso também deixa o código mais portável, já que os formatos de data podem mudar de banco para banco;
Permite que você use Strings, sem ter que se preocupar com caracteres como as aspas simples (considere o que ocorreria no seu código se um usuário inserisse aspas simples no endereço ou no nome);
Evita a falha de segurança de SQL Injection;
Deixa o código mais claro, já que evita aquele monte de concatenação;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class AmigoDAO {
Menus.Banco bancoAmigo = new Menus.Banco();
public List<Amigo> carregar() {
try {
List<Amigo> amigos = new ArrayList<Amigo>();
//Código para carregar os amigos do banco aqui
PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement("SELECT * FROM Amigos ORDER BY nome");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
//Criamos um novo amigo
Amigo amigo = new Amigo();
amigo.setCodigo(rs.getInt("codigo"));
amigo.setNome(rs.getString("nome"));
amigo.setEndereco(rs.getString("endereco"));
amigo.setBairro(rs.getString("bairro"));
amigo.setTelefone(rs.getString("Telefone"));
//Colocamos ele na lista
amigos.add(amigo);
}
//Retornamos a lista de amigos
return amigos;
} catch (SQLException e) {
//Se ocorrer erros, disparamos na forma de uma RuntimeException
//Isso evitará que tenhamos que ficar tratando erros que raramente ocorrem.
//E que não podemos fazer muita coisa para nos recuperar é o caso das SQLException.
throw new RuntimeException(e);
}
}
public void salvar(Amigo amigo) {
if (amigo.getCodigo() == -1) {
inserir(amigo); //Faz um INSERT no banco
} else {
atualizar(amigo); //Faz um UPDATE no banco.
}
}
public void inserir(Amigo amigo) {
try {
//Fazemos a inserção do amigo no banco
PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement(
"INSERT INTO Amigos (nome, endereco, bairro, tel) VALUES(?,?,?,?)");
stmt.setString(1, amigo.getNome());
stmt.setString(2, amigo.getEndereco());
stmt.setString(3, amigo.getBairro());
stmt.setString(4, amigo.getTelefone());
stmt.executeUpdate();
//Obtemos a chave criada automaticamente
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()) {
amigo.setCodigo(rs.getInt(1));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void atualizar(Amigo amigo) {
try {
//Fazemos a inserção do amigo no banco
java.sql.PreparedStatement stmt = bancoAmigo.con.prepareStatement(
"UPDATE INTO Amigos (nome, endereco, bairro, tel) VALUES(?,?,?,?)");
stmt.setString(1, amigo.getNome());
stmt.setString(2, amigo.getEndereco());
stmt.setString(3, amigo.getBairro());
stmt.setString(4, amigo.getTelefone());
stmt.executeUpdate();
//Obtemos a chave criada automaticamente
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()) {
amigo.setCodigo(rs.getInt(1));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
java.sql.PreparedStatement stmt = bancoAmigo.con.prepareStatement(
"UPDATE Amigos SET nome=?, endereco=?, bairro=?, tel=? WHERE codigo=?");
stmt.setString(1, amigo.getNome());
stmt.setString(2, amigo.getEndereco());
stmt.setString(3, amigo.getBairro());
stmt.setString(4, amigo.getTelefone());
stmt.setInt(5, amigo.getCodigo()); //Precisamos informar quem está sendo alterado
Não tente programar por tentativa e erro, aí não funciona mesmo. Procure pela sintaxe do SQL, senão não vai funcionar nunca. Mas minha grande frustração com SQL, e que nunca entendi, é pq nunca fizeram a sintaxe do INSERT e do UPDATE parecidas. Por mim, todas tinham que seguir a do update.
O INSERT deixa o nome dos campos longe dos valores, é dependente de ordem. Nenhum desses problemas ocorre na sintaxe do UPDATE.
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class AmigoDAO {
Menus.Banco bancoAmigo = new Menus.Banco();
public List<Amigo> carregar() {
try {
List<Amigo> amigos = new ArrayList<Amigo>();
//Código para carregar os amigos do banco aqui
PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement("SELECT * FROM Amigos ORDER BY nome");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
//Criamos um novo amigo
Amigo amigo = new Amigo();
amigo.setCodigo(rs.getInt("codigo"));
amigo.setNome(rs.getString("nome"));
amigo.setEndereco(rs.getString("endereco"));
amigo.setBairro(rs.getString("bairro"));
amigo.setTelefone(rs.getString("Telefone"));
//Colocamos ele na lista
amigos.add(amigo);
}
//Retornamos a lista de amigos
return amigos;
} catch (SQLException e) {
//Se ocorrer erros, disparamos na forma de uma RuntimeException
//Isso evitará que tenhamos que ficar tratando erros que raramente ocorrem.
//E que não podemos fazer muita coisa para nos recuperar é o caso das SQLException.
throw new RuntimeException(e);
}
}
public void salvar(Amigo amigo) {
if (amigo.getCodigo() == -1) {
inserir(amigo); //Faz um INSERT no banco
} else {
atualizar(amigo); //Faz um UPDATE no banco.
}
}
public void inserir(Amigo amigo) {
try {
//Fazemos a inserção do amigo no banco
PreparedStatement stmt = (PreparedStatement) bancoAmigo.con.prepareStatement(
"INSERT INTO Amigos (nome, endereco, bairro, tel) VALUES(?,?,?,?)");
stmt.setString(1, amigo.getNome());
stmt.setString(2, amigo.getEndereco());
stmt.setString(3, amigo.getBairro());
stmt.setString(4, amigo.getTelefone());
stmt.executeUpdate();
//Obtemos a chave criada automaticamente
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()) {
amigo.setCodigo(rs.getInt(1));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void atualizar(Amigo amigo) {
try {
//Fazemos a inserção do amigo no banco
java.sql.PreparedStatement stmt = bancoAmigo.con.prepareStatement(
"UPDATE Amigos SET nome=?, endereco=?, bairro=?, tel=? WHERE codigo=?");
stmt.setString(1, amigo.getNome());
stmt.setString(2, amigo.getEndereco());
stmt.setString(3, amigo.getBairro());
stmt.setString(4, amigo.getTelefone());
stmt.setInt(5, amigo.getCodigo()); //Precisamos informar quem está sendo alterado
stmt.executeUpdate();
//Obtemos a chave criada automaticamente
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()) {
amigo.setCodigo(rs.getInt(1));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Tudo em ordem? Se sim, qual seria o proximo passo?
Bom, o próximo passo é montar o TableModel.
Veja bem, agora vc tem um List<Amigo>, certo? Fica fácil carregar seus amigos do banco e salva-los lá. Chegou a hora de exibi-los.
package Teste;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
public class AmigoTableModel extends AbstractTableModel {
private static final int COL_CODIGO = 0;
private static final int COL_NOME = 1;
private static final int COL_ENDERECO = 2;
private static final int COL_BAIRRO = 3;
private static final int COL_TELEFONE = 4;
private List<Amigo> valores;
//Esse é um construtor, que recebe a nossa lista de livros
public TableModel(List<Amigo> valores) {
this.valores = new ArrayList<Amigo>(valores);
}
public int getRowCount() {
//Quantas linhas tem sua tabela? Uma para cada item da lista.
return valores.size();
}
public int getColumnCount() {
//Quantas colunas tem a tabela? Nesse exemplo, só 2.
return 2;
}
public String getColumnName(int column) {
//Qual é o nome das nossas colunas?
if (column == COL_CODIGO) {
return "Codigo";
}
if (column == COL_NOME) {
return "Nome";
}
if (column == COL_ENDERECO) {
return "Endereço";
}
if (column == COL_BAIRRO) {
return "Bairro";
}
if (column == COL_TELEFONE) {
return "Telefone";
}
return ""; //Nunca deve ocorrer
}
public Object getValueAt(int row, int column) {
//Precisamos retornar o valor da coluna column e da linha row.
Amigo titulo = valores.get(row);
if (column == COL_CODIGO) {
return titulo.getCodigo();
} else if (column == COL_NOME) {
return titulo.getNome().getNome();
} else if (column == COL_ENDERECO){
return titulo.getEndereco().getEndereco();
} else if (column == COL_BAIRRO){
return titulo.getBairro().getBairro();
} else if (column == COL_TELEFONE){
return titulo.getTelefone().getTelefone();
}
return ""; //Nunca deve ocorrer
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
//Vamos alterar o valor da coluna columnIndex na linha rowIndex com o valor aValue passado no parâmetro.
//Note que vc poderia alterar 2 campos ao invés de um só.
if (columnIndex == COL_NOME) {
titulo.setTitulo(aValue.toString());
} else if (columnIndex == COL_AUTOR) {
titulo.getAutor().setNome(aValue.toString());
}
}
public Class<?> getColumnClass(int columnIndex) {
//Qual a classe das nossas colunas? Como estamos exibindo texto, é string.
return String.class;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
//Indicamos se a célula da rowIndex e da columnIndex é editável. Nossa tabela toda é.
return true;
}
//Já que esse tableModel é de livros, vamos fazer um get que retorne um livro inteiro.
//Isso elimina a necessidade de chamar o getValueAt() nas telas.
public Amigo get(int row) {
return valores.get(row);
}
}
E por ai mesmo?
E nessa parte:
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
//Vamos alterar o valor da coluna columnIndex na linha rowIndex com o valor aValue passado no parâmetro.
//Note que vc poderia alterar 2 campos ao invés de um só.
if (columnIndex == COL_NOME) {
titulo.setTitulo(aValue.toString());
} else if (columnIndex == COL_AUTOR) {
titulo.getAutor().setNome(aValue.toString());
}
}
Aqui e necessario inserir todos os campos desde codigo ate telefone?
E esta variavel titulo, onde ela e declarada/criada?
No setValueAt vc põe todas as colunas que você queira que o usuário altere na sua tabela. Se sua tabela não for editável, o setValueAt pode estar completamente vazio. Como no isCellEditable vc indicou que todas as suas células são editáveis, então vc precisará colocar o código para todas as colunas.
O que acontece. O seu usuário dá dois cliques numa célula, que contém um valor:
O seu JTable chama o método isCellEditable para aquela célula. Se retornar true, então ele abrirá um editor e deixará o usuário editar a célula. Se o seu model retornar false, ele não deixará editar a célula;
O usuário digita no editor o novo valor para a célula;
O JTable chama o método setValueAt do model, indicando para ele esse novo valor. O model então atualiza o dado, se desejar;
O JTable chama o método getValueAt do model, para pegar o valor. O valor obtido será exibido.
Se seu setValueAt não alterar o objeto que está dentro do model, assim que o usuário sair do editor ele voltará a ver o valor antigo, antes da edição, já que quando a tabela chegar ao passo 4, ela voltará a obter o valor não modificado. Essa é a forma padrão de tratar entradas inválidas em tabelas.
Quanto ao setValueAt, faltou colocar a linha
Amigo titulo = valores.get(row);
Logo no início, como vc fez para o getValueAt. Outra coisa. A palavra “titulo” tem a ver com livros.
Troque o nome de titulo para amigo no seu caso.
Eu havia pensado em fazer um alterar da seguinte maneira:
Deixar a tabela somente para listar os registros, o usuario iria selecionar o registro e clicar no botao alterar, onde iria abrir uma tela com os dados carregados para poderem ser alterados.
public Object getValueAt(int row, int column) {
//Precisamos retornar o valor da coluna column e da linha row.
Amigo amigo = valores.get(row);
if (column == COL_CODIGO) {
return amigo.getCodigo();
} else if (column == COL_NOME) {
return amigo.getNome().getNome();
} else if (column == COL_ENDERECO) {
return amigo.getEndereco().getEndereco();
} else if (column == COL_BAIRRO) {
return amigo.getBairro().getBairro();
} else if (column == COL_TELEFONE) {
return amigo.getTelefone().getTelefone();
}
return ""; //Nunca deve ocorrer
}
Neste getValueAt, esta dando ero nos gets(Nome, Endereco, Bairro e Telefone):
Qual seria a ideia de usar dois get um seguido de outro?
Isso. Tente entender o que o método está fazendo. Ele é usado pelo JTable para perguntar para seu model. “Ei, o que eu desenho na linha line, coluna row?”
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
//Vamos alterar o valor da coluna columnIndex na linha rowIndex com o valor aValue passado no parâmetro.
//Note que vc poderia alterar 2 campos ao invés de um só.
Amigo amigo = valores.get(columnIndex);
if (columnIndex == COL_NOME) {
amigo.setNome(aValue.toString());
} else if (columnIndex == COL_ENDERECO) {
amigo.setEndereco(aValue.toString());
} else if (columnIndex == COL_BAIRRO) {
amigo.setEndereco(aValue.toString());
} else if (columnIndex == COL_TELEFONE){
amigo.setTelefone(aValue.toString());
}
}
Ja que e para alteração, o codigo deveria ser incluso no metodo acima?
Geralmente você não deixa o usuário alterar o código. Você até pode colocar ele numa das colunas, a título de informação para seu usuário. Mas deixe-a como não editável. Pra isso, basta retornar false naquele método “isEditable” para a coluna do código.
Quem vai alterar o código é apenas o sistema, quando o Amigo for salvo (que daí sairá de -1 para o código que ele usará para sempre).