Carregando JTable com dados do Apache Derby

Veja neste artigo como carregar dados no JTable através de dados populados no Apache Derby.

Neste artigo veremos como trabalhar com o componente JTable do Java, um dos mais completos e complexos do pacote Swing. Veremos o seu uso através de um exemplo completo, desde a definição dos Beans até a criação dos formulários.

Desenvolvimento do Projeto

Para nosso projeto utilizaremos o banco de dados nativo do Java, o Apache Derby. Começaremos configurando-o e criando um banco de dados para uso no nosso projeto. Para este artigo estamos utilizando a IDE Netbeans 7.2, mas fique à vontade para utilizar outra versão de sua preferência.

Com o NetBeans aberto, vá até a aba Serviços e depois clique duas vezes em “Banco de Dados”. Você verá a opção “Java DB”, que refere-se ao Apache Derby. Então clique com o botão direito do mouse e vá em “Criar banco de dados”. Logo em seguida aparecerá uma tela para que você possa preencher as propriedades do seu banco de dados; configuraremos da seguinte forma:

  1. Nome do Banco: dbusuario
  2. Nome do Usuário: root
  3. Senha: 1234

Feito isso, veremos a criação de um novo link jdbc:derby://localhost:1527/dbusuario. Clique com o botão direito neste link e vá em “Conectar”. Depois de conectado devemos clicar com o botão direito novamente e ir em Executar comando, assim, seremos redirecionados para uma tela onde poderemos digitar os comandos em SQL para criação da nossa tabela usuario, conforme a Listagem 1.

CREATE TABLE usuario( login varchar(50) not null primary key, senha varchar(50) not null, nome varchar(255) not null );
Listagem 1. SQL para criação da tabela usuário

Nossa tabela é bem simples e possui apenas três campos: login, senha e nome. Depois de colocar o comando da Listagem 1 na linha de comando do Derby basta executá-lo e já temos nossa estrutura do banco de dados pronta. Podemos agora partir para a codificação em Java.

Em Java precisamos garantir que a conexão com o banco de dados seja estabelecida, para isso criaremos uma classe chamada Conexao.java, conforme a Listagem 2, que terá por responsabilidade manter e retornar a conexão do banco de dados em aberta ou abrir uma caso não exista.

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package br.com.crudusuario.security; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class Conexao { private static Connection connection; public static Connection getConnection() throws ClassNotFoundException, SQLException{ if (connection == null){ Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); String url = "jdbc:derby://localhost:1527/dbusuario"; connection = DriverManager.getConnection(url, "root", "1234"); } return connection; } }
Listagem 2. Classe Conexao

A classe Conexao possui um atributo estático connection, que armazenará a conexão atual, ou seja, se ele for nulo, uma nova conexão será criada, caso contrário será apenas retornada a instância da conexão atual, evitando que sejam criadas diversas conexões. O nosso Class.forName() carrega o driver do Apache Derby para que possamos utilizá-lo, e o DriverManager.getConnection() retorna uma instância de Connection dado os parâmetros de conexão necessários.

Feito isto já temos a nossa conexão com o banco estabelecida a qualquer momento que precisarmos, basta chamado o método: Conexao.getConnection() e estaremos conectados.

Criamos o nosso banco e depois definimos uma forma de conexão via Java, agora iremos definir nossa regra de negócio necessária para a aplicação em questão. Nossa aplicação é muito simples e tem como objetivo listar os usuários cadastrados usando um JTable. Para que isso seja possível, o mais aconselhável é que nossa estrutura esteja pronta para suportar operações com o banco de dados, então começaremos definindo o nosso Bean, ou seja, a forma que temos de mapear a nossa tabela usuario do banco de dados para o Java. Veja a Listagem 3.

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package br.com.crudusuario.bean; /** * * @author LAB4-PC03 */ public class Usuario { private String login; private String senha; private String nome; public String getLogin() { return login; } public void setLogin(String login) { this.login = login; } public String getSenha() { return senha; } public void setSenha(String senha) { this.senha = senha; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } }
Listagem 3. Bean Usuario.java

Os métodos e atributos do bean são definidos de acordo com a nossa tabela usuario, já que ele é apenas um “espelho” da mesma.

Precisamos agora criar alguma classe que faça a comunicação do nosso ambiente gráfico de interação com o usuário (formulários) com o banco de dados. Por exemplo, quando o usuário clicar no botão “listar”, precisaremos de uma classe que vá até o banco e busque todos os usuários cadastrados para que estes possam ser mostrados no nosso formulário.

Poderíamos colocar essa lógica de comunicação com o banco de dados dentro do nosso formulário, mas esta não é uma boa prática, visto que se desejarmos realizar a mesma busca em outro formulário estaríamos repetindo código, então o melhor é centralizar essas operações em uma única classe, como mostra a Listagem 4.

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package br.com.crudusuario.dao; import br.com.crudusuario.bean.Usuario; import br.com.crudusuario.security.Conexao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public abstract class UsuarioDAO { public static Usuario getUsuarioByLogin(String login) throws ClassNotFoundException, SQLException { Connection con = Conexao.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM usuario WHERE login = ?", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ps.setString(1, login); return populaUsuario(ps.executeQuery()); } public static void deleteByLogin(String login) throws SQLException, ClassNotFoundException { Connection con = Conexao.getConnection(); PreparedStatement ps = con.prepareStatement("DELETE FROM usuario WHERE login = ?"); ps.setString(1, login); ps.execute(); } public static List<Usuario> getUsuarios() throws ClassNotFoundException, SQLException { Connection con = Conexao.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM usuario"); ResultSet rs = ps.executeQuery(); List<Usuario> usuarios = new ArrayList<Usuario>(); while (rs.next()) { Usuario usuario = new Usuario(); usuario.setLogin(rs.getString("login")); usuario.setNome(rs.getString("nome")); usuario.setSenha(rs.getString("senha")); usuarios.add(usuario); } return usuarios; } private static Usuario populaUsuario(ResultSet rs) throws SQLException { rs.first(); Usuario usuario = new Usuario(); usuario.setLogin(rs.getString("login")); usuario.setNome(rs.getString("nome")); usuario.setSenha(rs.getString("senha")); return usuario; } }
Listagem 4. Classe UsuarioDAO

Vamos entender melhor cada um dos nossos métodos apresentados:

  1. getUsuarioByLogin() : Dado um login qualquer, este método retorna uma instância de Usuario. Perceba que já fazemos o uso do Conexao.getConnection() e, logo em seguida, usamos um outro método chamado populaUsuario();
  2. deleteByLogin(): Deleta um determinado usuário de acordo com o login passado.
  3. getUsuarios(): É um dos nossos métodos principais, pois é quem irá popular nossa JTable. Este retorna uma lista de Usuários.
  4. populaUsuario(): Perceba que em quase todos os métodos fizemos o uso deste, pois este método converte o ResultSet para o Bean, que pode ser manipulado pela lógica do nosso sistema, assim não precisamos ficar trabalhando com ResultSet e sim direto com o Bean.

No NetBeans, clique com o botão direito em cima do seu projeto e vá em Novo -> Form JFrame…. Será criado um formulário onde devemos inserir o componente JTable e um JButton, como podemos ver na Figura 1.

Figura 1. Formulário para listagem de usuários

Precisamos agora definir os métodos necessários para inicializar nosso JTable corretamente. Este possui uma “ligação” com o TableModel, onde é possível realizarmos o mapeamento do nosso bean Usuario com a listagem, assim temos uma listagem dinâmica baseada no banco de dados. Observe a Listagem 5.

public FListaUsuario() throws ClassNotFoundException, SQLException { initComponents(); tabelaUsuarios = (DefaultTableModel) jTableUsuarios.getModel(); carregarUsuariosNoTable(); } private void carregarUsuariosNoTable() throws ClassNotFoundException, SQLException{ tabelaUsuarios.setNumRows(0); for (Usuario u : UsuarioDAO.getUsuarios()) { tabelaUsuarios.addRow(new Object[] { u.getNome(), u.getSenha(),u.getLogin() }); } }
Listagem 5. Inicializando JTable

Temos dois métodos importantes: o construtor do nosso formulário e um método responsável por carregar os usuários no nosso JTable. Logo que abrimos nosso formulário pela primeira vez o construtor é chamado e neste momento usamos o método getModel(), que nos retorna um objeto que implementa TableModel. Então nesse caso podemos usar o DefaultTableModel, que é uma das classes que implementa a interface TableModel. De posse do objeto DefaultTableModel na variável tabelaUsuarios, passaremos a trabalhar com ele para realizar as operações relativas ao banco de dados, como por exemplo, carregar os usuários na tabela.

O nosso método carregarUsuariosNoTable() é quem faz a tarefa de carregar os usuários retornados pela classe UsuarioDAO no JTable. Isso é feito setando o nosso TableModel com rows = 0 através do método setNumRows(0), assim garantimos que não há nenhum registro para evitar duplicações. Depois disso capturamos a lista de usuários através do UsuarioDAO.getListaUsuarios() e iteramos nesta lista, adicionando objeto por objeto através do método addRow() do TableModel.

Vejamos agora nosso método de deleção presente na Listagem 6.

private void jButtonDeletarActionPerformed(java.awt.event.ActionEvent evt) { if (JOptionPane.showConfirmDialog(this, "Tem certeza que deseja deletar este usuário ?") == JOptionPane.YES_OPTION){ String loginSelecionado = jTableUsuarios.getValueAt(jTableUsuarios.getSelectedRow(), 2).toString(); try { UsuarioDAO.deleteByLogin(loginSelecionado); JOptionPane.showMessageDialog(this, "Usuário deletado com sucesso"); carregarUsuariosNoTable(); } catch (SQLException ex) { Logger.getLogger(FListaUsuario.class.getName()).log(Level.SEVERE, null, ex); } catch (ClassNotFoundException ex) { Logger.getLogger(FListaUsuario.class.getName()).log(Level.SEVERE, null, ex); } } }
Listagem 6. Deleção de usuários

Na deleção do usuário confirmamos se é isto mesmo que deve ser feito e logo depois capturamos o valor do login de acordo com o número da linha selecionado. Por exemplo, se ele está na linha 2, então para nós será a linha 1 já que a contagem começa do 0. Sendo assim passamos a linha 1 como parâmetro e a coluna 2 (0 = nome, 1 = senha e 2 = login) e o usuário será deletado.

Logo após a deleção do usuário precisamos atualizar a lista com os novos usuários. Temos duas formas de fazer isso:

  1. Removendo a linha do JTable;
  2. Recarregando os usuários no JTable.

Claro que o método 1 é mais rápido, porém, para treinarmos o uso do método de carregamento através do banco de dados optamos por utilizar o método 2.

No JTable você deve usar o TableModel que usamos anteriormente, pois através deste você consegue manipular a maioria das funcionalidades dispostas no JTable, como mostra a Listagem 7.

import javax.swing.JTable; import javax.swing.table.DefaultTableModel; public class JTableTest { public static void main(String[] argv) throws Exception { DefaultTableModel model = new DefaultTableModel(); JTable table = new JTable(model); model.addColumn("Col1"); model.addRow(new Object[] { "r1" }); model.addRow(new Object[] { "r2" }); model.addRow(new Object[] { "r3" }); } }
Listagem 7. Adicionando colunas e linhas

Temos um exemplo simples de criação de um JTable, onde definimos um DefaultTableModel que implementa a interface TableModel. Através do DefaultTableModel controlamos as propriedades de colunas e linhas do JTable. Veja que na Listagem 7 usamos o addColumn() e o addRow(). O addRow() aceita um array onde cada item corresponde a coluna que inserimos anteriormente, e como usamos apenas uma coluna, nosso array sempre terá apenas um item. Veja como ficaria se tivéssemos mais colunas na Listagem 8.

import javax.swing.JTable; import javax.swing.table.DefaultTableModel; public class JTableTest { public static void main(String[] argv) throws Exception { DefaultTableModel model = new DefaultTableModel(); JTable table = new JTable(model); model.addColumn("Col1"); model.addColumn("Col2"); model.addRow(new Object[] { "r11","r12" }); model.addRow(new Object[] { "r21","r22" }); } }
Listagem 8. Adicionando várias e colunas e várias linhas

Perceba que a quantidade de objetos no nosso array aumentou para a mesma quantidade de colunas, esse é o princípio da manipulação colunas e linhas usando o DefaultTableModel.

Outro método interessante é o clearSelection(), que é responsável por limpar a seleção de qualquer linha que esteja selecionada, juntamente com outro método setRowSelectionInterval() responsável por selecionar uma quantidade de linhas desejadas. Com estes dois métodos podemos trabalhar com a manipulação de seleções do JTable. Vejamos a Listagem 9.

import javax.swing.JTable; import javax.swing.table.DefaultTableModel; public class JTableTest { public static void main(String[] argv) throws Exception { DefaultTableModel model = new DefaultTableModel(); JTable table = new JTable(model); model.addColumn("Col1"); model.addColumn("Col2"); model.addRow(new Object[] { "r11","r12", "r13" }); model.addRow(new Object[] { "r21","r22", "r23" }); table.setRowSelectionInterval(0, 1); table.clearSelection(); } }
Listagem 9. Trabalhando com seleção

Na linha setRowSelectionInterval(0,1) selecionamos as linhas 0 e 1 do nosso JTable e logo em seguida limpamos esta seleção através do clearSelecion(). Obviamente que estas linhas devem ser criadas previamente, por isso fizemos questão de repetir o código aonde adicionamos as colunas e as linhas.

É importante salientar que o método setRowSelecionInterval() trabalha com o conceito de que tanto a linha inicial e a linha final também serão selecionadas, e não apenas as que estão entre elas. Por exemplo, imagine que seu JTable possui 10 linhas (de 0 à 9), e você faz setRowSelecionInterval(4,8): isso irá selecionar as linhas: 4,5,6,7,8.

Além deste tipo de seleção mais específica, temos uma mais genérico e simples, selectAll() irá selecionar tudo, ou seja, linhas e colunas contidas no JTable.

Podemos também selecionar apenas as colunas com o método setColumnSelectionInterval(), onde devemos passar os índices das colunas iniciais e finais que gostaríamos de selecionar. Ele segue o mesmo princípio do setRowSelectionInterval, por isso não colocaremos listagem para tal.

Outro ponto importante da seleção é o getSelectedRow() e o getSelectedColumn(). Imagine que o usuário selecione alguma linha da tabela e clique no botão deletar (como fizemos anteriormente): o getSelectedRow() nos mostrará que linha foi selecionada, e por outro lado o getSelectedColumn() irá mostrar quando uma coluna for selecionada.

Vejamos agora o getColumnCount(), presente na Listagem 10, que nos ajudará a retornar a quantidade de colunas que nosso JTable possui.

import javax.swing.JTable; import javax.swing.table.DefaultTableModel; public class JTableTest { public static void main(String[] argv) throws Exception { DefaultTableModel model = new DefaultTableModel(); JTable table = new JTable(model); model.addColumn("Col1"); model.addColumn("Col2"); model.addColumn("Col3"); model.addColumn("Col4"); model.addColumn("Col5"); System.out.println(table.getColumnCount()); } }
Listagem 10. Retornando a quantidade de colunas

Temos aqui que o retorno será igual a 5, isso porque criamos cinco colunas no nosso Model.

Por último, vejamos um método também muito interessante para permitir a edição de uma célula em especial: editCellAt(int row, int column). Com este método podemos habilitar a edição de uma determinada célula para o usuário alterar o seu valor, como mostra a Listagem 11.

import javax.swing.JTable; import javax.swing.table.DefaultTableModel; public class JTableTest { public static void main(String[] argv) throws Exception { DefaultTableModel model = new DefaultTableModel(); JTable table = new JTable(model); model.addColumn("Col1"); model.addColumn("Col2"); model.addColumn("Col3"); model.addColumn("Col4"); model.addColumn("Col5"); int indexRow = table.getSelectedRow(); int indexColumn = table.getSelectedColumn(); if (!table.editCellAt(indexRow, indexColumn)){ System.err.println("Não foi possível habilitar a edição desta celula"); } System.out.println(table.getColumnCount()); } }
Listagem 11. Usando editCellAt() com getSelectedRow()

Veja que misturamos um pouco os conceitos aprendidos neste artigo. Capturamos o índice da coluna e da linha selecionada e tentamos habilitar a mesma para a edição. Caso tudo ocorra com sucesso, a edição será realizada, caso contrário iremos mostrar uma mensagem de erro no console.

O objetivo deste artigo vai muito além de apenas aprender o uso do JTable, mas sim a construção de um projeto básico de conexão com o banco de dados e listagem de usuários cadastrados.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados