17 de fev. de 2016

Um CRUD com JavaFX usando banco de dados

Devido ao sucesso da postagem anterior Um CRUD com JavaFX, resolvi estender a mesma para falar sobre o acesso a um banco de dados MySQL utilizando a mesma estrutura do artigo anterior.

Acessando banco de dados com Java


Esse é talvez um dos assuntos mais buscados por quem está aprendendo Java. Há muitas referências a isso na internet, inclusive uma série de artigos que o criado desse blog  escreveu há mais de 5 anos atrás para o JavaFree, veja: Acessando dados com Java: 1º parte - Simples Dao - Acessando Dados com Java: Parte 2 - Prevendo problemas - Acessando Dados com Java: Parte 3 - Hibernate Annotations

Preparando o banco

O primeiro passo nosso é garantir que você tenha o MySQL instalado(que depende do sistema operacional sendo utilizado, Linux ou outros) e uma vez feito isso, entre no MySQL e então seguir alguns passos. Para esse artigo foi criado o seguinte:


  • Usuário contas_app com senha aprendajavafx;

CREATE USER 'contas_app'@'localhost' IDENTIFIED BY 'aprendajavafx';


  •  Banco de dados contas crud-contas; 

CREATE DATABASE `crud-contas`  DEFAULT CHARACTER SET utf8  DEFAULT COLLATE utf8_general_ci


  • Garanta os privilégios do usuário contas_app para o banco crud-contas

mysql> use crud-contas
Database changed
mysql> GRANT ALL PRIVILEGES ON * . * TO 'contas_app'@'localhost';


  • Tabela Contas com os campos que precisamos

create table contas(  
   id int auto_increment, 
   concessionaria varchar(30) not null,  
   descricao varchar(1000) not null,  
   data_vencimento date not null,
   primary key(id)         
); 

Notem que o ID é auto_increment, ou seja, o MySQL vai dar o ID para nós. Se inserirmos alguns valores de teste, podemos notar que o ID já foi preenchido:

Criando uma classe para acesso ao banco de dados

Conforme falamos no artigo anterior, para trocar onde os dados serão armazenados nós iremos criar uma implementação de ContasService e trocar o tipo retornado no método getNewInstance

Para falarmos com o nosso banco de dados MySQL, precisamos ter o Driver JDBC no classpath da aplicação, pois é ele quem possibilita a comunicação de uma aplicação Java com o banco. Por isso, baixe o driver JDBC do MySQL e coloque no classpath da aplicação.

A implementação do banco de dados simplesmente envia comandos SQL para o MySQL invés de abrir e manipular arquivos, assim temos que:

* Salvar significa realizar um INSERT com os dados da conta passada;
* Buscar é trazer dados usando SELECT e transformar em uma lista de contas;
* Apagar é realizar um DELETE;
* Por fim atualizar é a realização de um UPDATE.

Claro que tudo pode ser facilitado usando um framework que faz o mapeamento de objetos para o modelo relacional de banco de dados, como o Hibernate, mas por hoje vamos ficar no básico! Finalmente, veja como ficou nossa classe ContasDBService (lembre-se que todo o código pode ser encontrado no github):


package org.aprendendojavafx.crud.service.impl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.aprendendojavafx.crud.model.Conta;
import org.aprendendojavafx.crud.service.ContasService;
/**
* Faz as operações de CRUD usando banco de dados MySQL. Para rodar essa classe
* vocë precisa <br />
* - Certificar-se que o driver do MySQL está no classpath da aplicação - Criar
* o banco de dados e atualizar o código abaixo de acordo com o seu banco -
* Criar a tabela contas.
*
* Se houver qualquer erro, o programa irá sair, assim, cheque os logs para ver o erro.
*
* @author wsiqueir
*
*/
public class ContasDBService implements ContasService {
// dados para acesso ao banco, atualize de acordo com o seu banco de dados
final String USUARIO = "contas_app";
final String SENHA = "aprendajavafx";
final String URL_BANCO = "jdbc:mysql://localhost:3306/crud-contas";
// constantes de acesso
final String CLASSE_DRIVER = "com.mysql.jdbc.Driver";
// comandos
final String INSERIR = "INSERT INTO contas(concessionaria, descricao, data_vencimento) VALUES(?, ?, STR_TO_DATE(?, '%d/%m/%Y'))";
final String ATUALIZAR = "UPDATE contas SET concessionaria=?, descricao=?, data_vencimento = STR_TO_DATE(?, '%d/%m/%Y') WHERE id = ?";
final String BUSCAR = "SELECT id, concessionaria, descricao, DATE_FORMAT(data_vencimento, %d/%m/%Y') FROM contas WHERE ID = ?";
final String BUSCAR_TODOS = "SELECT id, concessionaria, descricao, DATE_FORMAT(data_vencimento, '%d/%m/%Y') FROM contas";
final String APAGAR = "DELETE FROM contas WHERE id = ?";
// tratamento de data
final String FORMATO_DATA = "dd/MM/yyyy";
final SimpleDateFormat FORMATADOR = new SimpleDateFormat(FORMATO_DATA);
@Override
public void salvar(Conta conta) {
try {
Connection con = conexao();
PreparedStatement salvar = con.prepareStatement(INSERIR);
String dateStr = FORMATADOR.format(conta.getDataVencimento());
salvar.setString(1, conta.getConcessionaria());
salvar.setString(2, conta.getDescricao());
salvar.setString(3, dateStr);
salvar.executeUpdate();
salvar.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println("ERROR SALVANDO CONTA");
System.exit(0);
}
}
@Override
public List<Conta> buscarTodas() {
List<Conta> contas = new ArrayList<>();
try {
Connection con = conexao();
PreparedStatement buscarTodos = con.prepareStatement(BUSCAR_TODOS);
ResultSet resultadoBusca = buscarTodos.executeQuery();
while (resultadoBusca.next()) {
Conta conta = extraiConta(resultadoBusca);
contas.add(conta);
}
buscarTodos.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println("ERROR BUSCANDO TODAS AS CONTAS.");
System.exit(0);
}
return contas;
}
@Override
public Conta buscaPorId(int id) {
Conta conta = null;
try {
Connection con = conexao();
PreparedStatement buscar = con.prepareStatement(BUSCAR);
buscar.setInt(1, id);
ResultSet resultadoBusca = buscar.executeQuery();
resultadoBusca.next();
conta = extraiConta(resultadoBusca);
buscar.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println("ERROR BUSCANDO CONTA COM ID " + id);
System.exit(0);
}
return conta;
}
@Override
public void apagar(int id) {
try {
Connection con = conexao();
PreparedStatement apagar = con.prepareStatement(APAGAR);
apagar.setInt(1, id);
apagar.executeUpdate();
apagar.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println("ERROR APAGANDO CONTA COM ID " + id);
System.exit(0);
}
}
@Override
public void atualizar(Conta conta) {
try {
Connection con = conexao();
PreparedStatement atualizar = con.prepareStatement(ATUALIZAR);
String dateStr = FORMATADOR.format(conta.getDataVencimento());
atualizar.setString(1, conta.getConcessionaria());
atualizar.setString(2, conta.getDescricao());
atualizar.setString(3, dateStr);
atualizar.setInt(4, conta.getId());
atualizar.executeUpdate();
atualizar.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
System.err.println("ERROR ATUALIZANDO CONTA COM ID " + conta.getId());
System.exit(0);
}
}
// abre uma nova conexão com o banco de dados. Se algum erro for lançado
// aqui, verifique o erro com atenção e se o banco está rodando
private Connection conexao() {
try {
Class.forName(CLASSE_DRIVER);
return DriverManager.getConnection(URL_BANCO, USUARIO, SENHA);
} catch (Exception e) {
e.printStackTrace();
if(e instanceof ClassNotFoundException) {
System.err.println("VERIFIQUE SE O DRIVER DO BANCO DE DADOS ESTÁ NO CLASSPATH");
} else {
System.err.println("VERIFIQUE SE O BANCO ESTÁ RODANDO E SE OS DADOS DE CONEXÃO ESTÃO CORRETOS");
}
System.exit(0);
// o sistema deverá sair antes de chegar aqui...
return null;
}
}
// extrain o objeto Conta do result set
private Conta extraiConta(ResultSet resultadoBusca) throws SQLException, ParseException {
Conta conta = new Conta();
conta.setId(resultadoBusca.getInt(1));
conta.setConcessionaria(resultadoBusca.getString(2));
conta.setDescricao(resultadoBusca.getString(3));
Date dataVencimento = FORMATADOR.parse(resultadoBusca.getString(4));
conta.setDataVencimento(dataVencimento);
return conta;
}
}

5 comentários:

  1. Boa tarde, tenho muito interesse em aprender javafx conheço um pouco sobre java e em uma googlada encontrei este blog, por onde devo começar? Forte abraço!

    ResponderExcluir
    Respostas
    1. Olá! Comece por aqui -> http://aprendendo-javafx.blogspot.com.br/p/o-que-e-javafx.html

      Bons Estudos :)

      Excluir
  2. Boa noite, estou com uma dúvida, realizei o CRUD utilizando o banco de dados, como eu incluo a ação do botão salvar sendo que utilizo javafx FXML, utilizo o SceneBuilder para criar minhas telas, nessa parte do código não ficou claro como realizo essa operação, caso possa me ajudar, serei grato.
    Abraços.

    ResponderExcluir
  3. Bom dia,
    Estou com o seguinte problema em relação a data, no meu banco de dados MySql, a data está correta, quando exibo as informações em uma TableView, a data está vindo sempre com 1 dia a menos. Por exemplo: no banco esta: 12/09/2018, na TableView aparece 11/09/2018, o que pode estar ocasionando esse erro?
    Estou usando o Eclipse Oxygen, desde já agradeço

    ResponderExcluir