Lucas Mendes
#java#orm#jpa#hibernate#spring

Série: ORM, JPA e Hibernate — Do JDBC ao Spring Data JPA (Parte 4)

Migrando para Spring Boot e Spring Data JPA.

Depois de compreender como funciona a persistência utilizando JPA e Hibernate, explorar o ciclo de vida das entidades, utilizar o EntityManager, escrever consultas JPQL e implementar uma camada DAO manualmente, chegamos ao último passo desta série.

Neste artigo iremos migrar nossa aplicação para o ecossistema Spring Boot, utilizando Spring Data JPA para simplificar o acesso aos dados sem abrir mão dos conceitos estudados até aqui.

Ao contrário do que muitos imaginam, o Spring Data JPA não substitui a JPA nem o Hibernate. Na realidade, ele utiliza essas tecnologias internamente, oferecendo uma camada de abstração que reduz significativamente a quantidade de código que precisamos escrever.

Se nos artigos anteriores construímos toda a infraestrutura manualmente para compreender como a persistência funciona, agora veremos como o Spring automatiza grande parte desse trabalho.

#🎯 Objetivos

Ao final deste artigo você deverá ser capaz de:

  • criar um projeto Spring Boot utilizando o Spring Initializr;
  • configurar uma aplicação Spring Boot para utilizar PostgreSQL;
  • reutilizar entidades JPA já existentes em uma aplicação Spring;
  • compreender o papel do Spring Data JPA;
  • criar interfaces Repository;
  • implementar uma API REST simples;
  • realizar testes HTTP utilizando um cliente REST.

#📚 O que muda quando usamos Spring Boot?

Até aqui nossa aplicação possuía aproximadamente esta arquitetura:

Aplicação

DAO

EntityManager

Hibernate

JDBC

PostgreSQL

Grande parte do código que escrevemos estava relacionada à infraestrutura:

  • criação do EntityManagerFactory;
  • gerenciamento do EntityManager;
  • abertura e fechamento de transações;
  • implementação das operações CRUD;
  • gerenciamento da camada DAO.

No Spring Boot boa parte dessa infraestrutura passa a ser gerenciada automaticamente.

Nossa arquitetura passa a ser semelhante à seguinte:

Controller

Service

Repository (Spring Data JPA)

Hibernate

JDBC

PostgreSQL

Perceba que continuamos utilizando Hibernate e JPA.

O que muda é que o Spring Boot configura automaticamente diversos componentes da aplicação.


#🌱 Criando o projeto Spring Boot

Abra o Spring Initializr (https://start.spring.io).

Utilize as seguintes configurações:

  • Project: Maven
  • Language: Java
  • Spring Boot: versão estável mais recente
  • Java: 21
  • Empacotamento: Jar

Dependências:

  • Spring Web
  • Spring Data JPA
  • PostgreSQL Driver

Após gerar o projeto, importe-o no VS Code.

Outra opção é utilizar os recursos da extensão Spring Boot Extension Pack do VS Code para criar o projeto diretamente do editor. Para isso, pressione Ctrl+Shift+P e digite Spring Initializr. Siga as instruções para criar o projeto com as mesmas configurações mencionadas acima.


#⚙️ Configurando o banco de dados

Ao contrário da aplicação anterior, não utilizaremos mais um arquivo persistence.xml.

Toda a configuração será realizada através do arquivo:

src/main/resources/application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/cursos_pweb1
spring.datasource.username=postgres
spring.datasource.password=123456

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true

spring.jpa.properties.hibernate.format_sql=true

Observe que agora o Spring Boot cria automaticamente:

  • DataSource
  • EntityManagerFactory
  • EntityManager
  • gerenciamento de transações

Lembre-se de ajustar o nome do banco, usuário e senha conforme sua instalação do PostgreSQL.


#♻️ Reaproveitando as entidades

A boa notícia é que praticamente todas as entidades criadas nos artigos anteriores podem ser reaproveitadas.

As anotações

  • @Entity
  • @Id
  • @GeneratedValue
  • @Column
  • @ManyToOne
  • @OneToMany

continuam exatamente iguais.

Em muitos casos será necessário apenas ajustar os imports para utilizar os pacotes corretos da Jakarta Persistence.

Isso demonstra uma das grandes vantagens da JPA: como ela é uma especificação padronizada, o código permanece praticamente inalterado ao migrarmos para o Spring Boot.

Crie um pacote entities dentro do pacote base da aplicação. Então mova todas as entidades definidas e mapeadas na Parte 3 para esse pacote. Ajuste a definição do pacote em cada classe e verifique se os imports estão corretos.


#📦 Adeus DAO, Olá Repository

Na Parte 3 implementamos manualmente uma interface DAO e sua implementação utilizando o EntityManager. No Spring Data JPA essa implementação deixa de ser necessária.

Crie um pacote repositories dentro do pacote base da aplicação. Em seguida, crie uma interface InstrutorRepository dentro desse pacote com a seguinte definição:

@Repository
public interface InstrutorRepository
        extends JpaRepository<Instrutor, Long> {

}

No código acima, Instrutor é a entidade que será gerenciada e Long é o tipo do identificador da entidade. Só de criar essa interface, extendendo de JpaRepository, o Spring Data JPA já disponibiliza automaticamente os métodos básicos de persistência, como:

save()

findById()

findAll()

deleteById()

existsById()

Sem escrever nenhuma implementação. É exatamente aqui que percebemos a produtividade oferecida pelo Spring Data JPA.

Seguindo a mesma lógica, crie as interfaces Repository para as demais entidades da aplicação, todas estendendo de JpaRepository e dentro do pacote repositories. Usamos a convenção de nomenclatura NomeDaEntidadeRepository para facilitar a identificação da interface que gerencia cada entidade.

O padrão Repository é um dos padrões de projeto mais utilizados no desenvolvimento de aplicações Java. Ele define uma abstração para o acesso a dados, permitindo que a lógica de negócio interaja com os dados sem se preocupar com os detalhes de implementação do armazenamento e nem com o local de armazenamento.


#🧠 Consultas derivadas

Além dos métodos básicos, o Spring consegue criar consultas automaticamente apenas analisando o nome do método.

Por exemplo, crie a seguinte assinatura de método dentro da interface InstrutorRepository:

List<Instrutor> findByNomeContaining(String nome);

Sem escrever JPQL, o Spring gera automaticamente uma consulta equivalente a:

WHERE nome LIKE '%texto%'

Também podemos criar consultas personalizadas utilizando a anotação @Query, quando necessário.


#🌐 Criando nossa primeira API REST

Para disponibilizar os dados da aplicação pela Web criaremos um controlador REST. Crie um pacote controllers dentro do pacote base da aplicação. Em seguida, crie a classe InstrutorController com a seguinte definição:

@RestController
@RequestMapping("/instrutores")
public class InstrutorController {

    @Autowired
    private final InstrutorRepository repository;

    @GetMapping
    public List<Instrutor> listar() {
        return repository.findAll();
    }

    @PostMapping
    public Instrutor salvar(@RequestBody Instrutor instrutor) {
        return repository.save(instrutor);
    }

}

Breve explicação do código acima:

  • @RestController: define a classe como um controlador REST (ou seja, que retorna dados no formato JSON e não páginas HTML, observando sempre os métodos e códigos de status apropriados do HTTP);
  • @RequestMapping("/instrutores"): define a rota base para todos os métodos do controlador;
  • @Autowired: injeta automaticamente a dependência do InstrutorRepository;
  • @GetMapping: define o método que será chamado quando uma requisição HTTP GET for feita para a rota /instrutores;
  • @PostMapping: define o método que será chamado quando uma requisição HTTP POST for feita para a rota /instrutores;
  • @RequestBody: indica que o corpo da requisição HTTP será convertido automaticamente para um objeto Instrutor.

Observe que não utilizamos:

  • EntityManager;
  • transações explícitas;
  • implementação DAO.

O próprio Spring coordena esses componentes para nós.


#▶️ Executando a aplicação

Execute a classe principal gerada pelo Spring Boot. No VS Code, pressione Ctrl+Shift+P, digite Spring Boot e selecione a opção Spring Boot: Run. Em seguida, selecione a classe principal do projeto. Ou ainda, procure o ícone da extensão Spring Boot Dashboard na barra lateral do VS Code e clique no botão de play para iniciar a aplicação.

Caso tudo esteja configurado corretamente, a aplicação iniciará um servidor embarcado na porta 8080.

A API estará disponível em:

http://localhost:8080/instrutores

#🧪 Testando a API

Para validar nossa aplicação, vamos realizar dois testes simples utilizando um cliente REST como o Insomnia, Postman ou a extensão REST Client do VS Code.

#Teste 1 — Inserindo um instrutor

POST

http://localhost:8080/instrutores

Body:

{
  "nome": "Carlos Eduardo",
  "email": "carlos@example.com",
  "biografia": "Especialista em Java."
}

Resultado esperado:

  • código HTTP 201 Created (ou 200 OK, dependendo da implementação);
  • objeto persistido retornado na resposta;
  • registro criado no PostgreSQL.

#Teste 2 — Consultando todos os instrutores

GET

http://localhost:8080/instrutores

Resultado esperado:

[
  {
    "id": 1,
    "nome": "Carlos Eduardo",
    "email": "carlos@example.com",
    "biografia": "Especialista em Java."
  }
]

Agora confirme também o resultado diretamente no PostgreSQL.

Você perceberá que o Spring Data JPA executou automaticamente todas as operações necessárias utilizando o Hibernate internamente.


#📊 Comparando as abordagens

JPA + HibernateSpring Data JPA
Configuração manualConfiguração automática
EntityManager explícitoGerenciado pelo Spring
DAO implementado manualmenteRepository automático
Transações explícitasGerenciadas pelo Spring
CRUD implementado manualmenteCRUD pronto com JpaRepository

#🎓 Encerrando a série

Ao longo desta série percorremos uma evolução bastante comum no desenvolvimento de aplicações Java.

Começamos entendendo as limitações do JDBC e os desafios do mapeamento objeto-relacional. Em seguida, estudamos os fundamentos da JPA, aprendemos como o Hibernate implementa essa especificação, exploramos o funcionamento do EntityManager, do contexto de persistência, das transações e da JPQL, além de construir manualmente uma camada DAO para compreender o que acontece por trás das abstrações.

Neste último artigo demos o passo final: migramos a aplicação para o ecossistema Spring Boot e Spring Data JPA, reutilizando praticamente todo o modelo de domínio desenvolvido anteriormente. Essa migração evidencia um ponto importante: o Spring Data JPA não substitui os conceitos estudados, mas os organiza e automatiza, permitindo que o desenvolvedor concentre seus esforços na lógica de negócio em vez da infraestrutura de persistência.

A partir deste ponto, você já possui uma base sólida para estudar tópicos mais avançados do ecossistema Spring, como camadas de serviço, validação com Bean Validation, tratamento centralizado de exceções, paginação, autenticação com Spring Security e desenvolvimento de APIs REST mais completas.

Boa jornada nos próximos projetos! 🚀

Compatilhe esse post