[Grupo de Estudos – Java] Criando uma interface com conexão ao banco de dados MySQL

Olá pessoal, eu resolvi postar as três classes para criar uma interface entre banco de dados e usuários. Estava com receio de que fosse muita informação, mas assim como eu, o leitor deve saber o que está buscando.

Existem vários novos conceitos apresentados nas classes deste post. No término teremos uma simples agenda telefônica, mas pode ser o começo para grandes projetos.

Um deles é a organização do código. Existem várias formas de se organizar um código de classe Java. É possível deixar grande parte do código no construtor da classe, ou ainda no método main; contudo esta não é uma boa prática de desenvolvedores.

Para fazer este post eu perdi um tempo considerável para resolver um problema devido a desorganização do meu código. E quando achei a solução resolvi implementar a organização que encontrei nas pesquisas.

Além de apresentar três classes novas, vou novamente reforçar a ideia de instanciar objetos, trazendo a classe Relogio mais uma vez, com pequenas alterações, sendo a mais importante, a retirada do método main.

/**
 * @author Luciano Santos
 * @site www.analisedesistemas.wordpress.com
 */
package agenda;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import java.text.DecimalFormat;
import java.util.Calendar;

public class Relogio extends JFrame {
    JLabel lblHorario;//declarando componente

    //declarando variaveis
    int hh, mm, ss;
    Calendar hora;
    DecimalFormat formato;

    public Relogio() {
        setTitle("Relogio");//definindo o titulo da janela

        setSize(160, 50); //definindo tamanho
        setLayout(new FlowLayout());//definindo o layout da janela
        setLocationRelativeTo(null);//centralizando a janela

        lblHorario = new JLabel("");//configurando o label inicial
        add(lblHorario);//adicionando o label configurado a janela
        inicio(); //invocando o metodo inicio
    }
    public final void inicio() { //criando o metodo inicio
        Timer time = new Timer(0, ativar);
        time.start();
    }
    private String formatar(int num) {
        formato = new DecimalFormat("00");//configurando para que o valor usado apresente 2 digitos
        return formato.format(num);
    }
    public void horas() {//criando o metodo horas
        hora = Calendar.getInstance();
        hh = hora.get(Calendar.HOUR_OF_DAY);//registrando a hora
        mm = hora.get(Calendar.MINUTE);//registrando os minutos
        ss = hora.get(Calendar.SECOND);//registrando os segundos
        lblHorario.setText(formatar(hh) + ":" + formatar(mm) + ":" + formatar(ss));
    }
    ActionListener ativar = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            horas();//invocando o metodo horas
        }
    };
}

Se você usa o NetBeans, crie um pacote agenda e salve a classe acima. Em seguida criaremos a classe de conexão. Existem outras formas de trabalhar com a conexão do banco de dados, optei por esta classe por achá-la mais segura. Percebam que eu deixei comentado na própria classe o procedimento para criar um arquivo cujo armazenará as informações de acesso ao banco de dados. è importante que as instruções das linhas 23 a 25 da próxima classe sejam seguidas.

/**
 * alterado por Luciano Santos
 * @site www.analisedesistemas.wordpress.com
 */
package agenda;

import java.sql.*;
import java.io.*;

public class ConexaoDB {

    Connection conexao;
    FileInputStream fi;
    BufferedReader buff;
    String line = "";
    String[] lines = new String[30];
    int i = 0;

    public ConexaoDB() {
        try {
            fi = new FileInputStream("/home/luciano/NetBeansProjects/Agenda/db.conf");
            /*
             * Num bloco de notas [windows] ou gedit [linux] digite as seguintes
             * informacoes e salve o arquivo na pasta do projeto com o nome db.conf
             * e altere o endereco acima para o endereco do arquivo.
             *
             * ex: c:\netBeansProjects\agenda\db.conf
             * ============================>>>
            #hostname ou Endereco IP
            localhost
            #Nome da base de dados
            agenda
            #Nome de usuário MySQL
            luciano
            #senha MySQL (deixe a proxima linha em branco se nao usar senha)
            entrar
            #fim
             * ==============================<<<
             * o arquivo deve conter somente as 9 linhas acima com as devidas
             * alteracoes de nome de usuario e senha.
             */
            buff = new BufferedReader(new InputStreamReader(fi));
            i = 0;
            while ((line = buff.readLine()) != null) {
                lines[i] = line;
                i++;
            }
            String host = lines[1].trim();
            String baseDeDados = lines[3].trim();
            String usuario = lines[5].trim();
            String senha = lines[7].trim();
            try{
            conexao = DriverManager.getConnection("jdbc:mysql://" + host + "/" + baseDeDados, usuario, senha);
            System.out.println("Conexao com banco de dados realizada com sucesso");
            }catch (SQLException erro1){
            System.out.println("Erro de conexao - " + erro1);
            }
        } catch (Exception erro2) {
            System.out.println("Erro de arquivo - " + erro2);
        }
    }
}

Salve a classe acima no pacote agenda. Vários itens tem destaque nesta classe.

  • A leitura de um arquivo externo;
  • Localização de dados neste arquivo;
  • Comentários com instruções ao leitor
  • Tratamento de exceções, sejam exceções SQL ou não.
  • Conexão ao banco de dados com 1 linha de código [na verdade somente a linha 53 poderia ser usada para fazer a conexão, desde que os atributos fossem substituídos pelas devidas informações]
  • Retorno de conexão [linha 54, mas só é útil se estiver usando o try/catch para tratar as exceções]

É importante detectar o que faz cada trecho do código. O tratamento de exceções pode ser testado alterando o nome de usuário ou senha no arquivo criado, ou alterando o nome do próprio arquivo criado, mas primeiro veja tudo funcionando, antes de alterar algum trecho e não conseguir achar o erro.

Na próxima classe temos o mais simples modelo de tabela que encontrei na net, criado por Ricardo Artur Staroski.

A implementação de um modelo de tabela vai ser um desafio mais cedo ou mais tarde, então decidi optar por mais cedo. Eu poderia ter feito uma introdução com o DefaultTableModel, ou com lists, mas quis fazer uma abordagem prática. O modelo a seguir monta a tabela com os dados de uma consulta. Ele pode ser expandido para executar outras funções, mas por hora temos material novo suficiente para nos preocuparmos.

/**
 * Implementação de um TableModel para renderizar o ResultSet de
 * uma consulta ao banco
 *
 * @author Ricardo Artur Staroski
 */
package agenda;

import java.sql.*;
import java.util.*;
import javax.swing.table.*;

public class TabelaModelo extends AbstractTableModel {

    private static class Column {
        public final Class<?> CLASS;
        public final String NAME;

        public Column(final String name, final Class<?> type) {
            NAME = name;
            CLASS = type;
        }
    }

    private static class Row {
        public final Object [] VALUES ;
        public Row(final ResultSet rs) throws SQLException {
            final int columns = rs.getMetaData().getColumnCount();
            VALUES = new Object  [columns ];
            for (int i = 1; i <= columns; i++) {
                VALUES [i - 1] = rs.getObject(i);
            }
        }
    }
    private static final long serialVersionUID = 1L;
    private List<Column> columns;
    private List<Row> lines;

    public TabelaModelo(final ResultSet rs) throws SQLException,
            ClassNotFoundException {

        columns = new ArrayList<Column>();
        final ResultSetMetaData md = rs.getMetaData();
        final int count = md.getColumnCount();
        for (int i = 1; i <= count; i++) {
            columns.add(new Column(md.getColumnName(i), Class.forName(md.getColumnClassName(i))));
        }
        lines = new ArrayList<Row>();
        while (rs.next()) {
            lines.add(new Row(rs));
        }
    }
    @Override
    public Class<?> getColumnClass(final int columnIndex) {
        return columns.get(columnIndex).CLASS;
    }
    @Override
    public int getColumnCount() {
        return columns.size();
    }
    @Override
    public String getColumnName(final int column) {
        return columns.get(column).NAME;
    }
    @Override
    public int getRowCount() {
        return lines.size();
    }
    @Override
    public Object getValueAt(final int rowIndex, final int columnIndex) {
        return lines.get(rowIndex).VALUES [columnIndex ];
    }
    @Override
    public boolean isCellEditable(final int rowIndex, final int columnIndex) {
        return false;
    }
}

A classe acima também deve ser salva no pacote agenda.

Finalmente temos a classe Agenda, onde novamente eu apresento instruções comentadas no código da classe. Um dos motivos de usar este recurso, é dar o devido destaque ao ato de COMENTAR o código. Registrar informações que não são relevantes para o programa, mas sim para o programador. Como Java é uma linguagem que promove o reuso de código, pode ser que você reuse um código seu daqui 3 ou 6 meses, e seus comentários na criação vão te ajudar no reuso.

A classe Agenda traz uma série de novidades. Mas os destaques vão para:

  • Instanciar uma classe de conexão
  • Instanciar um modelo de tabela
  • Uso de métodos para organizar a criação da interface
/**
* @author Luciano Santos
*/
package agenda;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.text.MaskFormatter;

public class Agenda extends JFrame {

JTable tblAmigos;
JScrollPane scrlAmigos;
JTextField txtNome;
JFormattedTextField ftxtFone;
MaskFormatter mskTelefone;
JButton btnAddAmigo, btnDelAmigo, btnCorrigir, btnSair;
JLabel lblTitulo, lblNome, lblTelefone;
PreparedStatement pStmtAmigo;
ResultSet rsAmigo;
ConexaoDB dbAmigo;
TabelaModelo mdlAmigo;

public Agenda() {
setTitle("Agenda de telefones");
setSize(400, 375);
setLocationRelativeTo(null);

setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);

relogio();
botoes();
caixas();
rotulos();
tabela();
buscaAmigos();
}

public final void relogio() {
Relogio hora = new Relogio();

lblTitulo = hora.lblHorario;
lblTitulo.setBounds(150, 0, 120, 24);
add(lblTitulo);
}

public final void tabela() {
tblAmigos = new JTable();
tblAmigos.setBounds(20, 20, 350, 200);
add(tblAmigos);

scrlAmigos = new JScrollPane(tblAmigos);
scrlAmigos.setBounds(20, 20, 350, 200);
add(scrlAmigos);
}

public final void botoes() {
btnAddAmigo = new JButton("Adicionar");
btnAddAmigo.setBounds(220, 254, 150, 20);
btnAddAmigo.addActionListener(Add);
btnAddAmigo.setMnemonic(KeyEvent.VK_A);
add(btnAddAmigo);

btnSair = new JButton("Sair");
btnSair.setBounds(120, 314, 150, 20);
btnSair.addActionListener(Sair);
btnSair.setMnemonic(KeyEvent.VK_S);
add(btnSair);

btnDelAmigo = new JButton("Deletar");
btnDelAmigo.setBounds(200, 284, 170, 20);
btnDelAmigo.addActionListener(Del);
btnDelAmigo.setMnemonic(KeyEvent.VK_D);
add(btnDelAmigo);

btnCorrigir = new JButton("Corrigir");
btnCorrigir.setBounds(20, 284, 165, 20);
btnCorrigir.addActionListener(Update);
btnCorrigir.setMnemonic(KeyEvent.VK_C);
add(btnCorrigir);
}

public final void rotulos() {
lblNome = new JLabel("Nome:");
lblNome.setBounds(20, 227, 150, 20);
add(lblNome);

lblTelefone = new JLabel("Telefone:");
lblTelefone.setBounds(20, 254, 150, 20);
add(lblTelefone);
}

public final void caixas() {
txtNome = new JTextField(30);
txtNome.setBounds(70, 227, 220, 20);
add(txtNome);
try {
mskTelefone = new MaskFormatter("(##) ####-####");
} catch (ParseException erro) {
System.out.println("Erro - " + erro);
}
ftxtFone = new JFormattedTextField(mskTelefone);
ftxtFone.setBounds(90, 254, 120, 20);
add(ftxtFone);
}
/*Use os seguintes comandos no mySQL para criar o banco de dados
create database agenda;
use agenda;
create table amigos (idAmigo int (7) AUTO_INCREMENT PRIMARY KEY, nome varchar(30), telefone varchar (15));
desc amigos;
*/
public String CONSULTA_PADRAO = "SELECT * FROM amigos ORDER BY nome";

public final void buscaAmigos() {
try {
dbAmigo = new ConexaoDB();
pStmtAmigo = dbAmigo.conexao.prepareStatement(CONSULTA_PADRAO);
rsAmigo = pStmtAmigo.executeQuery();

mdlAmigo = new TabelaModelo(rsAmigo);
tblAmigos.setModel(mdlAmigo);

rsAmigo.close();
pStmtAmigo.close();
dbAmigo.conexao.close();
} catch (SQLException erro1) {
System.out.println("Erro na Query - " + erro1);
} catch (ClassNotFoundException erro2) {
System.out.println("Erro ao pegar a classe - " + erro2);
}
}
public String INSERCAO = "INSERT INTO amigos (nome,telefone) VALUES (?,?)";
ActionListener Add = new ActionListener() {

@Override
public void actionPerformed(ActionEvent clic) {
try {
dbAmigo = new ConexaoDB();
pStmtAmigo = dbAmigo.conexao.prepareStatement(INSERCAO);

if (!txtNome.getText().equals("") && !ftxtFone.getText().equals("")) {// tratamento logico
pStmtAmigo.setString(1, txtNome.getText());
pStmtAmigo.setString(2, ftxtFone.getText());

int retorno = pStmtAmigo.executeUpdate();
System.out.println(retorno + " linha inserida - Nome: " + txtNome.getText());
} else {
JOptionPane.showMessageDialog(rootPane, "Insira um nome e um número de telefone", "Aviso", JOptionPane.WARNING_MESSAGE);
}
pStmtAmigo.close();
dbAmigo.conexao.close();
} catch (SQLException erro2) {
System.out.println("Erro ao inserir - " + erro2);
}
buscaAmigos();//atualizando a tabela apresentada
ftxtFone.requestFocus();//levando o cursor para um novo telefone
}
};
public String DELECAO = "DELETE FROM amigos WHERE idAmigo =  (?)";
ActionListener Del = new ActionListener() {

@Override
public void actionPerformed(ActionEvent clic) {
try {
dbAmigo = new ConexaoDB();
pStmtAmigo = dbAmigo.conexao.prepareStatement(DELECAO);
String idAmigo = "0";
if (!idAmigo.equals("")) {// tratamento logico
pStmtAmigo.setString(1, JOptionPane.showInputDialog("Qual o id do amigo a ser excluido?"));
int retorno = pStmtAmigo.executeUpdate();
System.out.println(retorno + " linha excluida - id " + idAmigo);
} else {
JOptionPane.showMessageDialog(rootPane, "Insira um id válido", "Aviso", JOptionPane.WARNING_MESSAGE);
}
pStmtAmigo.close();
dbAmigo.conexao.close();
} catch (SQLException erro2) {
System.out.println("Erro ao excluir - " + erro2);
}
buscaAmigos();//atualizando a tabela apresentada
ftxtFone.requestFocus();//levando o cursor para um novo telefone
}
};
public String CORRECAO = "UPDATE amigos SET nome = (?), telefone = (?) WHERE idAmigo =  (?)";
ActionListener Update = new ActionListener() {

@Override
public void actionPerformed(ActionEvent clic) {
JTextField idAmigo = new JTextField();
JTextField nome = new JTextField();
JFormattedTextField fone = new JFormattedTextField(mskTelefone);
final JComponent[] inputs = new JComponent[]{
new JLabel("Digite os dados corretos:\n idAmigo"),
idAmigo,
new JLabel("Nome"),
nome,
new JLabel("Telefone"),
fone
};
JOptionPane.showMessageDialog(null, inputs, "Corrigir registro", JOptionPane.PLAIN_MESSAGE);
try {
dbAmigo = new ConexaoDB();
pStmtAmigo = dbAmigo.conexao.prepareStatement(CORRECAO);

if (!idAmigo.getText().equals("") && !nome.getText().equals("") && !fone.getText().equals("")) {// tratamento logico
pStmtAmigo.setString(1, nome.getText());
pStmtAmigo.setString(2, fone.getText());
pStmtAmigo.setString(3, idAmigo.getText());
int retorno = pStmtAmigo.executeUpdate();
System.out.println(retorno + " linha atualizada - id " + idAmigo.getText());
} else {
JOptionPane.showMessageDialog(rootPane, "Preencha todos os dados para correção", "Aviso", JOptionPane.WARNING_MESSAGE);
}
pStmtAmigo.close();
dbAmigo.conexao.close();
} catch (SQLException erro2) {
System.out.println("Erro ao excluir - " + erro2);
}
buscaAmigos();//atualizando a tabela apresentada
ftxtFone.requestFocus();//levando o cursor para um novo telefone
}
};
ActionListener Sair = new ActionListener() {

@Override
public void actionPerformed(ActionEvent click) {
System.exit(0);
}
};

public static void main(String[] args) {
Agenda amigos = new Agenda();
amigos.setVisible(true);
}
}

O código acima apresenta várias novidades para quem tem acompanhado os posts do grupo de estudo. Entre elas está o uso de métodos para organizar a interface. Quando usamos o gerenciador de layout nulo é possível organizar o código da forma que lhe convier. No método caixas() vimos pela primeira vez o uso de campos formatados, neste caso usando uma máscara de telefone; da linha 112 a 116 a máscara é criada e aplicada na 117.

Os métodos botoes(), caixas(), rotulos() e  tabela() poderiam ser colados no método construtor sem trazer problemas, contudo a maneira apresentada facilita a detecção de erros, ou a execução de alterações necessárias.

O método relogio() instancia a classe Relogio, do começo deste post.

Depois dos métodos de interface, temos o método de consulta buscaAmigos(). Ele faz a conexão com com banco e manda uma query, definida na constante CONSULTA_PADRAO, em seguida passa as informações para o modelo de tabela, renderizando a tabela logo em seguida. Antes de terminar o método todas as instruções e conexões são fechadas.

A partir da linha 147 temos os ActionListener dos quatro botões  da interface, os três botões relacionados a operações no banco de dados contém várias novidades, uma delas seria o tratamento lógico. Eu utilizei um desvio condicional para verificar se os campos foram preenchidos, evitando campos incompletos na base de dados.

Outra novidade foi o uso de janelas de diálogos, através do JOptionPane, no ActionListener Del, nós vemos a forma mais comum de uso, com showInputDialog e showMessageDialog. No ActionListener Update eu mostro um diálogo personalizado.

É claro que está classe também deve ser salva no pacote agenda, estando pronta para rodar.

Muita coisa foi apresentada neste post, então aguardo as dúvidas nos comentários.Eis a saída das classes:

14 Respostas para “[Grupo de Estudos – Java] Criando uma interface com conexão ao banco de dados MySQL

  1. ola meu querido amei, este post, tava louco para fazer uma GUI com o BD, mas eutbm queria aprender fazer um calendário, tipo com os 12 meses, os dia sera q vc poderia me ajudar?
    abraços

  2. É exatamente isso que eu precisava… eu estou a começar agora e esse ajuda muito… depois de implementar vou incomodar-te com duvidas! Valeu

  3. Eu fiz tudo mas agora me deparo com esse erro de conexão e não sei uke fazer, ajuda-me por favor.

    Exception in thread “main” java.lang.NullPointerException
    Erro de conexao – java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost/agenda
    at agenda.Agenda.buscaAmigos(Agenda.java:139)
    at agenda.Agenda.(Agenda.java:58)
    at agenda.Agenda.main(Agenda.java:254)

  4. Show de bola o post, sou iniciante e consegui assimilar legal como a coisa funciona. Tentei gerar o .jar e retornou a mensagem: “Could not find the main class: agenda.Agenda. Program will exit.”. O que fiz errado?

    • Seguinte, fuçando aqui alterei o formato código-fonte/binário de JDK 7 para JDK 6 e consegui fazer o .jar funcionar.

    • o programa está dentro de um pacote agenda, quando se usa o netbeans ele cria os pacotes durante a criação do projeto… os pacotes nada mais são do que pastas…

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s