Operações CRUD: Dominando a Manipulação de Dados em Aplicações Web
Aprenda a construir aplicações completas para criar, consultar, atualizar e excluir dados em sistemas web utilizando Java, JDBC e JSP. Domine as técnicas essenciais para desenvolvimento de sistemas modernos com persistência de dados.
Objetivos da Aula
Compreensão Completa do CRUD
Entenda o ciclo completo de operações em sistemas web e como implementá-las em Java.
Formulários Dinâmicos
Desenvolva interfaces interativas que se integram perfeitamente com o banco de dados.
Padrões de Desenvolvimento
Explore JavaBeans, DAO e outros padrões essenciais para persistência de dados em aplicações Java.
Esta aula combina 1 hora de teoria fundamental com 3 horas de prática intensiva, permitindo que você aplique imediatamente os conceitos aprendidos em projetos reais.
O que é CRUD?
CRUD representa as quatro operações fundamentais de persistência:
  • Create (Criar) - Inserção de novos registros
  • Read (Ler) - Consulta e recuperação de dados
  • Update (Atualizar) - Modificação de registros existentes
  • Delete (Excluir) - Remoção de dados
Estas operações formam a base de praticamente qualquer sistema que precise armazenar dados de forma persistente, desde aplicações web simples até sistemas empresariais complexos.
Importância das Operações CRUD
1
Fundamento para Sistemas de Informação
O CRUD constitui a espinha dorsal de qualquer sistema que precise manipular dados, sendo a base para implementação de regras de negócio mais complexas.
2
Abstração de Interações
Simplifica a interação com bancos de dados, permitindo operações consistentes independente da tecnologia de armazenamento utilizada.
3
Padronização de Interfaces
Estabelece um padrão comum para desenvolvimento de interfaces e APIs, facilitando a manutenção e evolução dos sistemas.
Dominar estas operações é essencial para qualquer desenvolvedor que deseja criar aplicações robustas e escaláveis.
Exemplos do Mundo Real de CRUD
Gerenciamento de Produtos
Lojas virtuais como Mercado Livre e Magazine Luiza utilizam operações CRUD para cadastrar, exibir, atualizar preços e remover produtos do catálogo.
Cadastro de Usuários
Redes sociais como Facebook e Instagram implementam CRUD para gerenciar perfis, permitindo criação de contas, visualização de informações, atualização de dados e exclusão de perfis.
Sistemas de Reserva
Aplicativos como Airbnb e sistemas de agendamento médico utilizam CRUD para gerenciar disponibilidade, consultar opções, modificar datas e cancelar reservas.
Modelagem dos Dados para CRUD
Definição de Entidades
Antes de implementar operações CRUD, é necessário definir claramente as entidades do sistema e seus atributos essenciais.
  • Identificar os objetos principais do domínio
  • Determinar relacionamentos entre entidades
  • Especificar restrições e regras de negócio
Estrutura de Dados
CREATE TABLE usuarios ( id INT PRIMARY KEY AUTO_INCREMENT, nome VARCHAR(100) NOT NULL, email VARCHAR(100) UNIQUE, senha VARCHAR(255), data_cadastro TIMESTAMP DEFAULT NOW() );
A modelagem adequada garante a integridade dos dados e facilita a implementação das operações CRUD de forma eficiente.
JavaBeans: Estrutura de Dados em Java
O que são JavaBeans?
JavaBeans são classes Java que seguem convenções específicas para representar entidades de dados de forma padronizada:
  • Possuem um construtor sem argumentos
  • Implementam a interface Serializable
  • Encapsulam atributos com getters e setters
  • Facilitam o mapeamento objeto-relacional
public class Pessoa implements Serializable { private int id; private String nome; private String email; // Construtor sem argumentos public Pessoa() { } // Getters e Setters 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 getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
Introdução ao DAO (Data Access Object)
Conceito
O DAO é um padrão de projeto que isola a lógica de acesso a dados do restante da aplicação, proporcionando uma interface clara para as operações CRUD.
Estrutura
Geralmente implementado como uma interface com métodos abstratos para operações básicas, com implementações concretas para cada tipo de banco.
Desacoplamento
Permite trocar a implementação de persistência sem afetar as camadas de negócio e apresentação da aplicação.
Manutenção
Facilita a manutenção do código por centralizar as operações de banco de dados em classes específicas.
Escalabilidade
Permite escalar a aplicação independentemente da tecnologia de persistência utilizada.
Diagrama: JavaBean + DAO
1
JavaBean
Representa a entidade com seus atributos e comportamentos encapsulados
2
DAO
Contém a lógica de acesso aos dados e converte entre objetos e registros
3
Banco de Dados
Armazena os dados de forma persistente em tabelas relacionais
Esta arquitetura promove a separação de responsabilidades, facilitando a manutenção e evolução do sistema ao longo do tempo.
Implementação CRUD Básica em Java
public interface PessoaDAO { // Create public void inserir(Pessoa pessoa) throws SQLException; // Read public Pessoa buscarPorId(int id) throws SQLException; public List listarTodos() throws SQLException; // Update public void atualizar(Pessoa pessoa) throws SQLException; // Delete public void excluir(int id) throws SQLException; }
A interface DAO define os métodos que toda implementação deve fornecer, estabelecendo um contrato claro para as operações CRUD. Os métodos lançam SQLException para permitir tratamento adequado de erros de banco de dados.
Esta abordagem modular facilita a manutenção e os testes unitários, além de permitir múltiplas implementações para diferentes tecnologias de persistência.
Integração Java com Banco de Dados usando JDBC
O que é JDBC?
JDBC (Java Database Connectivity) é uma API Java que permite a conexão e execução de operações em bancos de dados relacionais, independentemente do banco utilizado.
Por que usar JDBC?
  • API padrão da plataforma Java
  • Suporte a diversos bancos de dados
  • Controle de transações
  • Execução de consultas SQL diretas
Etapas de Uso do JDBC
Carregamento do Driver
Class.forName("com.mysql.cj.jdbc.Driver");
Estabelecimento da Conexão
Connection conn = DriverManager.getConnection(url, user, password);
Criação de Statements
PreparedStatement stmt = conn.prepareStatement(sql);
Execução de Queries
ResultSet rs = stmt.executeQuery(); ou stmt.executeUpdate();
Exemplo Prático: Método insert() no DAO
public void inserir(Pessoa pessoa) throws SQLException { // SQL com placeholders para evitar SQL Injection String sql = "INSERT INTO pessoas (nome, email) VALUES (?, ?)"; // Try-with-resources garante fechamento dos recursos try ( Connection conn = ConnectionFactory.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) ) { // Substituição dos placeholders por valores reais stmt.setString(1, pessoa.getNome()); stmt.setString(2, pessoa.getEmail()); // Executa a inserção e retorna número de linhas afetadas int affectedRows = stmt.executeUpdate(); if (affectedRows == 0) { throw new SQLException("Falha ao inserir, nenhuma linha afetada."); } // Recupera o ID gerado pelo banco try (ResultSet generatedKeys = stmt.getGeneratedKeys()) { if (generatedKeys.next()) { pessoa.setId(generatedKeys.getInt(1)); } } } }
Exemplo Prático: Método read() no DAO
public Pessoa buscarPorId(int id) throws SQLException { String sql = "SELECT id, nome, email FROM pessoas WHERE id = ?"; try ( Connection conn = ConnectionFactory.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql) ) { stmt.setInt(1, id); try (ResultSet rs = stmt.executeQuery()) { if (rs.next()) { Pessoa pessoa = new Pessoa(); pessoa.setId(rs.getInt("id")); pessoa.setNome(rs.getString("nome")); pessoa.setEmail(rs.getString("email")); return pessoa; } else { return null; // Nenhuma pessoa encontrada com o ID } } } } public List listarTodos() throws SQLException { String sql = "SELECT id, nome, email FROM pessoas"; List pessoas = new ArrayList<>(); try ( Connection conn = ConnectionFactory.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql); ResultSet rs = stmt.executeQuery() ) { while (rs.next()) { Pessoa pessoa = new Pessoa(); pessoa.setId(rs.getInt("id")); pessoa.setNome(rs.getString("nome")); pessoa.setEmail(rs.getString("email")); pessoas.add(pessoa); } } return pessoas; }
Exemplo Prático: Método update() no DAO
public void atualizar(Pessoa pessoa) throws SQLException { String sql = "UPDATE pessoas SET nome = ?, email = ? WHERE id = ?"; try ( Connection conn = ConnectionFactory.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql) ) { // Configurando autocommit como false para controle de transação conn.setAutoCommit(false); try { stmt.setString(1, pessoa.getNome()); stmt.setString(2, pessoa.getEmail()); stmt.setInt(3, pessoa.getId()); int affectedRows = stmt.executeUpdate(); if (affectedRows == 0) { throw new SQLException("Falha ao atualizar, nenhuma linha afetada."); } // Confirma a transação conn.commit(); } catch (Exception e) { // Desfaz alterações em caso de erro conn.rollback(); throw e; } finally { // Restaura configuração padrão conn.setAutoCommit(true); } } }
Boas Práticas de Atualização
  • Use transações para garantir consistência dos dados
  • Verifique o número de linhas afetadas para confirmar sucesso
  • Faça rollback em caso de exceções
  • Sempre restaure o autoCommit para seu estado original
  • Utilize try-with-resources para fechamento automático de recursos

O método update() permite modificar registros existentes no banco de dados sem criar duplicações, mantendo a integridade referencial.
Exemplo Prático: Método delete() no DAO
public void excluir(int id) throws SQLException { String sql = "DELETE FROM pessoas WHERE id = ?"; try ( Connection conn = ConnectionFactory.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql) ) { stmt.setInt(1, id); int affectedRows = stmt.executeUpdate(); if (affectedRows == 0) { throw new SQLException("Falha ao excluir, registro não encontrado."); } } catch (SQLIntegrityConstraintViolationException e) { // Tratamento específico para violações de integridade throw new SQLException("Não é possível excluir. " + "Este registro possui dependências em outras tabelas.", e); } }
Tratamento de Restrições de Integridade
Ao excluir registros, é essencial considerar as restrições de chaves estrangeiras para evitar inconsistências nos dados.
Exclusão em Cascata
Configure a restrição ON DELETE CASCADE para excluir registros dependentes automaticamente.
Violações de Integridade
Capture SQLIntegrityConstraintViolationException para fornecer mensagens claras ao usuário.
Formulários Dinâmicos em HTML e JSP
Formulários Estáticos vs. Dinâmicos
Exemplo: Select Dinâmico com JSP
<%@ page import="java.util.List" %> <%@ page import="dao.CategoriaDAO" %> <%@ page import="model.Categoria" %> <% CategoriaDAO categoriaDAO = new CategoriaDAO(); List<Categoria> categorias = categoriaDAO.listarTodos(); %> <select name="categoria" id="categoria" class="form-control"> <option value="">Selecione uma categoria</option> <% for(Categoria cat : categorias) { %> <option value="<%= cat.getId() %>"> <%= cat.getNome() %> </option> <% } %> </select>
Os formulários dinâmicos permitem criar interfaces adaptáveis que refletem o estado atual dos dados no banco, proporcionando uma melhor experiência ao usuário.
Construção de Formulários Dinâmicos
Usando JSTL para Iteração
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!-- Configurando atributos no servlet --> <!-- request.setAttribute("produtos", produtoDAO.listarTodos()); --> <select name="produto"> <c:forEach items="${produtos}" var="produto"> <option value="${produto.id}">${produto.nome} - R$ ${produto.preco}</option> </c:forEach> </select>
Usando Scriptlets JSP
<% List<Estado> estados = estadoDAO.listarTodos(); String estadoSelecionado = request.getParameter("estado"); %> <select name="estado" id="estado"> <% for(Estado estado : estados) { %> <option value="<%= estado.getUf() %>" <%= estado.getUf().equals(estadoSelecionado) ? "selected" : "" %>> <%= estado.getNome() %> </option> <% } %> </select>
A geração dinâmica de formulários permite adaptar a interface de acordo com os dados disponíveis, as permissões do usuário e o contexto da aplicação, melhorando significativamente a experiência do usuário.
Validação de Dados no Formulário
Validação no Cliente (HTML5)
<input type="email" name="email" required pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$" title="Digite um email válido"> <input type="tel" name="telefone" required pattern="[0-9]{10,11}" title="Digite apenas números (DDD + número)">
Validação no Servidor (Java)
// Em um servlet ou controller String email = request.getParameter("email"); String nome = request.getParameter("nome"); String cpf = request.getParameter("cpf"); List<String> erros = new ArrayList<>(); if (email == null || email.trim().isEmpty()) { erros.add("Email é obrigatório"); } else if (!email.matches("[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$")) { erros.add("Email inválido"); } if (nome == null || nome.trim().length() < 3) { erros.add("Nome deve ter pelo menos 3 caracteres"); } if (cpf == null || !validarCPF(cpf)) { erros.add("CPF inválido"); } if (!erros.isEmpty()) { request.setAttribute("erros", erros); request.getRequestDispatcher("/formulario.jsp").forward(request, response); return; }
Feedback Visual ao Usuário
<c:if test="${not empty erros}"> <div class="alert alert-danger"> <ul> <c:forEach items="${erros}" var="erro"> <li>${erro}</li> </c:forEach> </ul> </div> </c:if> <c:if test="${not empty sucesso}"> <div class="alert alert-success"> ${sucesso} </div> </c:if>
Comportamento Dinâmico dos Formulários
Campos Condicionais com JavaScript
<script> function toggleFields() { var tipoPessoa = document.getElementById("tipoPessoa").value; if (tipoPessoa === "PF") { document.getElementById("camposCPF").style.display = "block"; document.getElementById("camposCNPJ").style.display = "none"; } else if (tipoPessoa === "PJ") { document.getElementById("camposCPF").style.display = "none"; document.getElementById("camposCNPJ").style.display = "block"; } } </script> <select id="tipoPessoa" name="tipoPessoa" onchange="toggleFields()"> <option value="PF">Pessoa Física</option> <option value="PJ">Pessoa Jurídica</option> </select> <div id="camposCPF"> <label for="cpf">CPF:</label> <input type="text" id="cpf" name="cpf"> </div> <div id="camposCNPJ" style="display:none"> <label for="cnpj">CNPJ:</label> <input type="text" id="cnpj" name="cnpj"> </div>
Expressões Condicionais em JSP
<c:choose> <c:when test="${usuario.tipo == 'ADMIN'}"> <!-- Campos específicos para administradores --> <div class="form-group"> <label for="nivelAcesso">Nível de Acesso:</label> <select name="nivelAcesso"> <option value="1">Básico</option> <option value="2">Intermediário</option> <option value="3">Total</option> </select> </div> </c:when> <c:when test="${usuario.tipo == 'CLIENTE'}"> <!-- Campos específicos para clientes --> <div class="form-group"> <label for="interesses">Interesses:</label> <input type="text" name="interesses"> </div> </c:when> </c:choose>
Integração de Formulário HTML/JSP com JavaBean
Mapeamento de Formulário para Bean
<form action="PessoaServlet" method="post"> <input type="hidden" name="id" value="${pessoa.id}"> <div class="form-group"> <label for="nome">Nome:</label> <input type="text" id="nome" name="nome" value="${pessoa.nome}" required> </div> <div class="form-group"> <label for="email">Email:</label> <input type="email" id="email" name="email" value="${pessoa.email}" required> </div> <button type="submit">Salvar</button> </form>
Recebimento no Servlet
@WebServlet("/PessoaServlet") public class PessoaServlet extends HttpServlet { private PessoaDAO pessoaDAO = new PessoaDAOImpl(); @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { // Recupera parâmetros do formulário String idStr = request.getParameter("id"); String nome = request.getParameter("nome"); String email = request.getParameter("email"); // Cria e preenche o bean Pessoa pessoa = new Pessoa(); if (idStr != null && !idStr.isEmpty()) { pessoa.setId(Integer.parseInt(idStr)); } pessoa.setNome(nome); pessoa.setEmail(email); // Decide entre inserir ou atualizar if (pessoa.getId() == 0) { pessoaDAO.inserir(pessoa); request.setAttribute("mensagem", "Pessoa inserida com sucesso!"); } else { pessoaDAO.atualizar(pessoa); request.setAttribute("mensagem", "Pessoa atualizada com sucesso!"); } } catch (Exception e) { request.setAttribute("erro", "Erro: " + e.getMessage()); } request.getRequestDispatcher("/pessoas.jsp") .forward(request, response); } }
Ligação do Formulário com a Lógica CRUD
1
Formulário JSP
Interface de usuário para entrada e exibição de dados
  • Coleta dados do usuário
  • Realiza validação inicial
  • Envia requisição para o Servlet
2
Servlet/Controller
Processa a requisição e coordena as operações
  • Mapeia parâmetros para JavaBeans
  • Valida dados recebidos
  • Chama métodos do DAO
3
DAO
Executa as operações CRUD no banco de dados
  • Converte JavaBeans em queries SQL
  • Executa operações no banco
  • Retorna resultados ou exceções
Este fluxo garante a separação de responsabilidades e facilita a manutenção da aplicação, além de permitir o reuso de componentes em diferentes partes do sistema.
Exemplo Completo: Formulário + Bean + DAO + Banco
1
HTML/JSP (Formulário)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Cadastro de Produto</title> </head> <body> <h1>Cadastro de Produto</h1> <c:if test="${not empty mensagem}"> <div>${mensagem}</div> </c:if> <form action="ProdutoServlet" method="post"> <input type="hidden" name="id" value="${produto.id}"> <div> <label for="nome">Nome:</label> <input type="text" id="nome" name="nome" value="${produto.nome}" required> </div> <div> <label for="preco">Preço:</label> <input type="number" id="preco" name="preco" step="0.01" value="${produto.preco}" required> </div> <div> <label for="categoria">Categoria:</label> <select id="categoria" name="categoriaId" required> <option value="">Selecione...</option> <c:forEach items="${categorias}" var="categoria"> <option value="${categoria.id}" <c:if test="${categoria.id == produto.categoria.id}">selected</c:if>> ${categoria.nome} </option> </c:forEach> </select> </div> <button type="submit">Salvar</button> </form> <h2>Produtos Cadastrados</h2> <table border="1"> <tr> <th>ID</th> <th>Nome</th> <th>Preço</th> <th>Categoria</th> <th>Ações</th> </tr> <c:forEach items="${produtos}" var="prod"> <tr> <td>${prod.id}</td> <td>${prod.nome}</td> <td>R$ ${prod.preco}</td> <td>${prod.categoria.nome}</td> <td> <a href="ProdutoServlet?acao=editar&id=${prod.id}">Editar</a> <a href="ProdutoServlet?acao=excluir&id=${prod.id}" onclick="return confirm('Confirma exclusão?')">Excluir</a> </td> </tr> </c:forEach> </table> </body> </html>
2
Java (Servlet e DAO)
@WebServlet("/ProdutoServlet") public class ProdutoServlet extends HttpServlet { private ProdutoDAO produtoDAO = new ProdutoDAOImpl(); private CategoriaDAO categoriaDAO = new CategoriaDAOImpl(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String acao = request.getParameter("acao"); try { if ("editar".equals(acao)) { int id = Integer.parseInt(request.getParameter("id")); Produto produto = produtoDAO.buscarPorId(id); request.setAttribute("produto", produto); } else if ("excluir".equals(acao)) { int id = Integer.parseInt(request.getParameter("id")); produtoDAO.excluir(id); request.setAttribute("mensagem", "Produto excluído com sucesso!"); } request.setAttribute("categorias", categoriaDAO.listarTodos()); request.setAttribute("produtos", produtoDAO.listarTodos()); } catch (Exception e) { request.setAttribute("erro", "Erro: " + e.getMessage()); } request.getRequestDispatcher("/produtos.jsp").forward(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { // Recupera parâmetros String idStr = request.getParameter("id"); String nome = request.getParameter("nome"); String precoStr = request.getParameter("preco"); String categoriaIdStr = request.getParameter("categoriaId"); // Converte e valida double preco = Double.parseDouble(precoStr); int categoriaId = Integer.parseInt(categoriaIdStr); // Busca categoria Categoria categoria = categoriaDAO.buscarPorId(categoriaId); // Cria produto Produto produto = new Produto(); if (idStr != null && !idStr.isEmpty()) { produto.setId(Integer.parseInt(idStr)); } produto.setNome(nome); produto.setPreco(preco); produto.setCategoria(categoria); // Salva if (produto.getId() == 0) { produtoDAO.inserir(produto); request.setAttribute("mensagem", "Produto inserido com sucesso!"); } else { produtoDAO.atualizar(produto); request.setAttribute("mensagem", "Produto atualizado com sucesso!"); } // Prepara para próxima exibição request.setAttribute("categorias", categoriaDAO.listarTodos()); request.setAttribute("produtos", produtoDAO.listarTodos()); } catch (Exception e) { request.setAttribute("erro", "Erro: " + e.getMessage()); } request.getRequestDispatcher("/produtos.jsp").forward(request, response); } }
3
SQL (Banco de Dados)
CREATE TABLE categorias ( id INT AUTO_INCREMENT PRIMARY KEY, nome VARCHAR(100) NOT NULL ); CREATE TABLE produtos ( id INT AUTO_INCREMENT PRIMARY KEY, nome VARCHAR(100) NOT NULL, preco DECIMAL(10,2) NOT NULL, categoria_id INT, FOREIGN KEY (categoria_id) REFERENCES categorias(id) ); INSERT INTO categorias (nome) VALUES ('Eletrônicos'), ('Informática'), ('Celulares');
Persistência e Transações
Controle de Transações em JDBC
// Exemplo de transação completa em JDBC Connection conn = null; try { conn = ConnectionFactory.getConnection(); // Desabilita o autocommit para iniciar transação conn.setAutoCommit(false); // Operação 1: Atualizar saldo da conta origem PreparedStatement stmt1 = conn.prepareStatement( "UPDATE contas SET saldo = saldo - ? WHERE id = ?"); stmt1.setDouble(1, valor); stmt1.setInt(2, contaOrigem); int rows1 = stmt1.executeUpdate(); // Operação 2: Atualizar saldo da conta destino PreparedStatement stmt2 = conn.prepareStatement( "UPDATE contas SET saldo = saldo + ? WHERE id = ?"); stmt2.setDouble(1, valor); stmt2.setInt(2, contaDestino); int rows2 = stmt2.executeUpdate(); // Verifica se ambas as operações afetaram linhas if (rows1 > 0 && rows2 > 0) { // Confirma a transação conn.commit(); } else { // Desfaz a transação conn.rollback(); throw new SQLException("Falha na transferência."); } } catch (Exception e) { // Em caso de erro, desfaz a transação if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } throw e; } finally { // Restaura o autocommit if (conn != null) { try { conn.setAutoCommit(true); conn.close(); } catch (SQLException ex) { ex.printStackTrace(); } } }
Princípios ACID
Atomicidade
Todas as operações da transação são executadas com sucesso ou nenhuma é aplicada.
Consistência
A transação leva o banco de um estado consistente para outro igualmente consistente.
Isolamento
Transações concorrentes não interferem umas nas outras.
Durabilidade
Uma vez confirmada (commit), a transação permanece mesmo em caso de falha do sistema.
Boas Práticas em CRUD e DAO
Padronização
  • Nomes consistentes para métodos (inserir, buscar, atualizar, excluir)
  • Nomenclatura clara para tabelas e colunas
  • Tratamento uniforme de exceções
  • Documentação de interfaces
Separação de Responsabilidades
  • DAO só contém lógica de acesso a dados
  • Lógica de negócio fica em classes de serviço
  • Validações divididas entre camadas
  • Servlet/Controller coordena o fluxo
Segurança e Desempenho
  • Sempre use PreparedStatement (nunca concatene SQL)
  • Gerencie conexões adequadamente
  • Utilize pool de conexões em produção
  • Implemente paginação para grandes conjuntos
Manutenibilidade
  • Código DRY (Don't Repeat Yourself)
  • Métodos pequenos e coesos
  • Factory para criação de DAOs
  • Tratamento centralizado de erros
Seguir estas práticas garante um código mais limpo, seguro e fácil de manter, além de facilitar a evolução da aplicação e a adição de novas funcionalidades no futuro.
Testando Operações CRUD
Casos de Teste Essenciais
1
Inserção
  • Dados válidos
  • Dados inválidos/incompletos
  • Duplicação de chaves únicas
2
Consulta
  • Busca por ID existente
  • Busca por ID inexistente
  • Listagem com filtros
3
Atualização
  • Atualização completa
  • Atualização parcial
  • Registro inexistente
4
Exclusão
  • Exclusão de registro existente
  • Exclusão de registro inexistente
  • Violação de integridade referencial
Exemplo de Classe de Teste
import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class PessoaDAOTest { private PessoaDAO dao; private Pessoa pessoa; @Before public void setUp() { dao = new PessoaDAOImpl(); pessoa = new Pessoa(); pessoa.setNome("Teste"); pessoa.setEmail("teste@example.com"); } @Test public void testInserir() throws SQLException { dao.inserir(pessoa); assertTrue(pessoa.getId() > 0); Pessoa recuperada = dao.buscarPorId(pessoa.getId()); assertEquals(pessoa.getNome(), recuperada.getNome()); assertEquals(pessoa.getEmail(), recuperada.getEmail()); } @Test public void testAtualizar() throws SQLException { dao.inserir(pessoa); pessoa.setNome("Teste Atualizado"); dao.atualizar(pessoa); Pessoa recuperada = dao.buscarPorId(pessoa.getId()); assertEquals("Teste Atualizado", recuperada.getNome()); } @Test public void testExcluir() throws SQLException { dao.inserir(pessoa); dao.excluir(pessoa.getId()); Pessoa recuperada = dao.buscarPorId(pessoa.getId()); assertNull(recuperada); } @Test(expected = SQLException.class) public void testInserirEmailDuplicado() throws SQLException { dao.inserir(pessoa); Pessoa outraPessoa = new Pessoa(); outraPessoa.setNome("Outro"); outraPessoa.setEmail("teste@example.com"); // Mesmo email dao.inserir(outraPessoa); // Deve lançar SQLException } }
Ferramentas Utilizadas na Aula
VS Code
Editor de código leve e extensível, com excelente suporte para Java, JSP, HTML e outras linguagens web através de extensões. Recomendado para desenvolvimento integrado de aplicações web.
JDBC
API Java para conexão com bancos de dados relacionais. Fornece classes e interfaces para estabelecer conexões, executar queries SQL e processar resultados de forma padronizada.
HTML/JSP
Tecnologias para criação de interfaces web. O HTML define a estrutura básica, enquanto JSP permite incorporar código Java para gerar conteúdo dinâmico no servidor.
SGBDs Populares
Extensões Recomendadas para VS Code
  • Extension Pack for Java - Suporte completo ao Java
  • Spring Boot Extension Pack - Para projetos Spring
  • Tomcat for Java - Integração com servidor Tomcat
  • JSP Support - Syntax highlighting para JSP
  • SQL Tools - Cliente SQL integrado
Recomendações de Segurança
Prevenção de SQL Injection
Sempre utilize PreparedStatement ao invés de Statement com concatenação de strings para evitar injeção de SQL malicioso.
// NUNCA FAÇA ISSO: String sql = "SELECT * FROM usuarios WHERE email = '" + email + "'"; Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); // FAÇA ISSO: String sql = "SELECT * FROM usuarios WHERE email = ?"; PreparedStatement stmt = conn.prepareStatement(sql); stmt.setString(1, email); ResultSet rs = stmt.executeQuery();
Validação de Entradas
Nunca confie em dados fornecidos pelo usuário. Sempre valide todas as entradas tanto no cliente quanto no servidor.
  • Verifique tipos de dados esperados
  • Valide faixas de valores
  • Sanitize strings removendo caracteres perigosos
  • Use expressões regulares para garantir formatos corretos
Controle de Acesso
Implemente autenticação e autorização adequadas para proteger operações sensíveis.
  • Verifique permissões antes de executar operações CRUD
  • Não exponha IDs sequenciais facilmente previsíveis
  • Implemente token CSRF em formulários
  • Use HTTPS para proteger dados em trânsito
Dicas para Projetos Práticos
Controle de Erros
try { // Lógica de negócio dao.inserir(objeto); // Mensagem de sucesso request.setAttribute("mensagem", "Operação realizada com sucesso!"); } catch (SQLException e) { // Log detalhado para depuração logger.error("Erro ao inserir: " + e.getMessage(), e); // Mensagem amigável para o usuário String msgUsuario = "Não foi possível realizar a operação."; if (e.getErrorCode() == 1062) { // MySQL duplicate key msgUsuario = "Este registro já existe no sistema."; } else if (e.getErrorCode() == 1451) { // MySQL foreign key msgUsuario = "Este registro não pode ser excluído pois está sendo usado em outro cadastro."; } request.setAttribute("erro", msgUsuario); } finally { // Redirecionamento consistente request.getRequestDispatcher("/pagina.jsp") .forward(request, response); }
Organização Modular
Estrutura de Pacotes
  • model - JavaBeans e entidades
  • dao - Interfaces e implementações DAO
  • controller - Servlets e controladores
  • util - Classes utilitárias
  • service - Lógica de negócio
Documentação
  • Javadoc em interfaces e métodos públicos
  • Comentários explicando lógica complexa
  • README com instruções de configuração
  • Modelo de dados documentado
Invista tempo em uma boa organização e documentação desde o início do projeto. Isso economizará muito mais tempo durante o desenvolvimento e manutenção.
Exercício Prático Proposto
Cadastro de Produtos
Desenvolva um sistema CRUD completo para gerenciamento de produtos. O sistema deve permitir:
  • Inserção de novos produtos com nome, descrição, preço e categoria
  • Consulta de produtos por ID ou filtros (nome, categoria)
  • Atualização de informações de produtos existentes
  • Exclusão de produtos (com confirmação)
  • Listagem paginada de todos os produtos

Utilize JavaBeans, padrão DAO e formulários dinâmicos conforme visto na aula. O sistema deve validar entradas e fornecer feedback claro ao usuário.
Modelo de Dados Sugerido
CREATE TABLE categorias ( id INT PRIMARY KEY AUTO_INCREMENT, nome VARCHAR(50) NOT NULL ); CREATE TABLE produtos ( id INT PRIMARY KEY AUTO_INCREMENT, nome VARCHAR(100) NOT NULL, descricao TEXT, preco DECIMAL(10,2) NOT NULL, estoque INT NOT NULL DEFAULT 0, categoria_id INT, data_cadastro TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (categoria_id) REFERENCES categorias(id) );
Prazo de entrega: próxima aula. O código deve seguir as boas práticas discutidas e ser enviado com instruções de configuração do ambiente.
Conclusão e Próximos Passos
Operações CRUD
Dominamos os fundamentos da manipulação de dados com Java e bancos relacionais.
2
2
Padrões DAO e JavaBeans
Aplicamos padrões que organizam o código e facilitam a manutenção.
Formulários Dinâmicos
Criamos interfaces que interagem com o banco e apresentam dados de forma eficiente.
Segurança e Boas Práticas
Implementamos técnicas para proteger dados e criar código sustentável.
Leituras Complementares Recomendadas
  • Padrão MVC (Model-View-Controller) e sua implementação em Java
  • Frameworks ORM como Hibernate e JPA para simplificar o acesso a dados
  • Spring Framework e sua abordagem para injeção de dependências
  • Testes automatizados para aplicações web com JUnit e Mockito
Na próxima aula, exploraremos técnicas avançadas de desenvolvimento web e a integração com frameworks modernos para acelerar a criação de aplicações robustas.