Como construir uma API de gestão financeira com Java, Spring Boot, JPA, Hibernate e H2 - Parte I
Este artigo é destinado para todos aqueles que possuem conhecimento intermediário na linguagem de programação Java, incluindo também os conceitos e princípios da Programação Orientada a Objetos (POO) e conhecimentos conceituais básicos de SQL.
Aos que são iniciantes e entusiastas da linguagem, indico o conteúdo do Gabriel Reis Duarte, responsável por fazer o Guia inicial de Java dentro da plataforma da Revelo para quem está começando. Também indico aos iniciantes a seguinte formação, cheia de exercícios práticos, da Universidade de Helsinki: Java Programming.
Este artigo está repleto de referências. Não tenha medo de tirar um tempo para olhar ou ler na íntegra cada uma delas. Algumas estão em inglês, então também não tenha receio de utilizar ferramentas de tradução que vão te permitir um bom entendimento de algo que foi escrito em outro idioma.
Ao longo deste artigo, será iniciado a criação de uma API REST para gestão financeira, usando os seguintes Frameworks: Spring, JPA, Hibernate e H2, cada um deles possui um propósito específico que será apresentado mais a frente. O sistema tem como base o diagrama de exemplo a seguir:
Não se preocupe em entender todo o diagrama agora com esta primeira imagem, tudo será apresentado aos poucos ao longo do artigo.
Devido à complexidade e profundidade do conteúdo, este artigo será dividido em três, portanto, segue o link para a segunda e para a terceira parte parte:
- Como construir uma API de gestão financeira utilizando Java, Spring Boot, JPA, Hibernate e H2 - Parte II
- Como construir uma API de gestão financeira utilizando Java, Spring Boot, JPA, Hibernate e H2 - Parte III
O projeto utilizado como base para este artigo se encontra neste repositório do GitHub.
Para que serve cada framework?
Antes de tudo, precisa-se entender o que é um framework e para que serve. Em poucas palavras, a tradução literal de “framework” é “ferramenta”, o framework é um conjunto de bibliotecas cheias de funções, estruturas e métodos que servem para facilitar o desenvolvimento de uma aplicação, nesse caso, serão utilizados frameworks diferentes para facilitar o desenvolvimento de partes diferentes do sistema.
Spring
O framework Spring possui diversas outras ferramentas dentro dele e, para este artigo, serão apresentados e utilizados apenas o Spring Boot e o Spring Web.
Spring Boot
O Spring Boot é responsável pela: configuração automática do projeto, usando como base as ferramentas de construção de projeto Maven ou Gradle;
Neste projeto, será utilizado Maven.
Spring Web
Utilizado para a criação de serviços da Web que utilizam o protocolo SOAP. Basicamente será necessário para que seja possível se comunicar utilizando as regras de mensageria adotadas pela Internet.
JPA
Utilizado para que seja possível persistir objetos Java utilizando da técnica de ORM em conjunto com o banco de dados H2.
Hibernate
Funciona em conjunto com o JPA também para realizar o mapeamento de objetos, visando persistir no banco de dados.
Sendo assim, qual seria a diferença entre o Hibernate e o JPA? Seria um bom ponto de pesquisa para que você leitor possa aprofundar posteriormente, mas, resumindo: o JPA é uma especificação Java sobre como se implementa um ORM e o Hibernate é o Framework em si que implementa o JPA e fornece funcionalidades de criação, leitura, atualização e deleção de objetos persistidos no banco de dados.
H2
É o banco de dados que será utilizado no projeto para persistir cada informação necessária nas respectivas tabelas. Esse banco de dados foi escrito em Java e foi escolhido devido à facilidade na utilização. Por ser um banco de dados em memória, não é necessário instalar nada no computador. É uma ferramenta muito comum para utilização de testes em Java devido à praticidade.
API de gestão financeira
A API vai servir para que um usuário consiga informar receitas e despesas, também podendo classificá-las de acordo com categorias criadas pelo próprio usuário. Cada categoria ou despesa também terá um status.
Projeto
Dentro deste capítulo estão concentrados todos os passos envolvendo o código do projeto e algumas explicações voltadas para a explicação das decisões tomadas.
O projeto será estruturado em três camadas:
1) Entidade
- Local onde ficarão todas as classes que definem cada objeto que será utilizado pelo sistema. Exemplos: Usuario, Receita, Despesa.
2) Recurso
- Local onde estarão todas as chamadas à API, responsáveis por receber a requisição e enviar uma resposta.
3) Serviço
- Local onde estarão as regras lógicas que serão utilizadas para manusear as entidades e acessar os repositórios.
4) Repositório
- Local onde será utilizado o JPA para acessar os dados que estarão armazenados no banco H2.
Criando o projeto
Para facilitar a criação do projeto, recomendo a utilização do site oficial da Spring chamado Spring Initializr para inicializar um projeto utilizando Spring Boot.
1) Acesse o Spring Initializr;
2) Segue um exemplo de preenchimento das opções:
- Project: Maven
- Language: Java
- Spring Boot: 3.0.5 (dependendo da época, será necessário uma versão mais recente)
- Group: br.com.caiocv18 (colocar o próprio site de maneira invertida)
- Artifact: artigojava (informe o nome do projeto)
- Name: artigojava (informe o nome do projeto novamente)
- Packaging: Jar
- Java: 17
- Dependencies > ADD DEPENDECIES > Spring Web
3) Clique em GENERATE;
4) Baixe o arquivo;
5) Descompacte em uma pasta de própria escolha;
6) Abra o IntelliJ ou uma IDE também de própria escolha;
7) Abra o projeto de acordo com a pasta escolhida;
8) Execute a aplicação:
9) Acessar localhost:8080 pelo navegador de própria escolha;
ℹ️ Link do meu commit relacionado aos passos realizados acima: https://github.com/caiocv18/artigojava/commit/dfb28b7dc68f770a60fc77fc0b0cc6da4af7e9e9
Usuário
Para a classe Usuário, teremos apenas os atributos a seguir:
- id;
- nome;
- email;
- senha.
Com os métodos get e set para cada atributo.
Devido às anotações e funções que serão utilizadas, também se faz necessário a criação dos métodos equals e hashCode.
Criando a entidade Usuário
Siga os passos a seguir para a criação a primeira entidade, visando seguir a estrutura de projeto apresentada anteriormente:
1) Crie um pacote chamado entidades;
2) Crie a classe Usuario;
3) Adicione os atributos como private:
- int id;
- String nome;
- String email;
- String senha;
ℹ️ O atributo id será fundamental para a utilização de ORM e para persistir no banco de dados posteriormente.
4) Crie um construtor vazio;
ℹ️ Esse construtor é necessário devido ao uso do framework Hibernate. Para entender melhor, veja a discussão sobre esse assunto no Stack Overflow.
5) Crie um construtor com todos os atributos;
6) Gere os getters e setters;
7) Gere hashcode e equals (selecionar apenas o atributo de ID para fazer a comparação);
8) Implementar a interface Serializable;
ℹ️ Serializable serve para: transformar os objetos em cadeias de bytes para que os mesmos possam trafegar numa rede, serem gravados em arquivos e etc.
9) Adicione o número de série padrão sugerido pelo próprio IntelliJ para o Serializable.
Criando o recurso Usuário
1) Crie um pacote de recursos
2) Crie uma classe UsuarioRecurso
3) Adicione a anotação @RestController acima da classe
ℹ️ Controlador necessário para manipular a classe em questão e serializar o objeto gerado para que seja possível enviar e receber na web.
4) Adicione a anotação abaixo da anterior para @RequestMapping passando como parâmetro (value = "/usuarios")
5) Crie um método com base na tipagem ResponseEntity<T> onde é passado o tipo da entidade como no lugar de T: ResponseEntity<Usuario>
public ResponseEntity<Usuario> findAll{
}
6) Retorne um objeto novo, apenas para teste
Usuario novoUsuario = new Usuario(1, "Caio", "caiocv18_dev@gmail.com","6199999999","12345")
return ResponseEntity.ok().body(u);
7) Adicione anotação para o tipo de requisição do método, colocando a Annotation @GetMapping
8) Por fim, a classe fica da seguinte forma:
package br.com.caiocv18.artigojava.recursos;
import br.com.caiocv18.artigojava.entidades.Usuario;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/usuarios")
public class UsuarioRecurso {
@GetMapping
public ResponseEntity<Usuario> procurarTodos(){
Usuario novoUsuario = new Usuario(1, "Caio", "caiocv18_dev@gmail.com", "12345");
return ResponseEntity.ok().body(novoUsuario);
}
}
Ao final, será possível acessar [localhost:8080/usuarios](<http://localhost:8080/usuarios>) e visualizar o usuário que foi instanciado no exemplo acima:
Acessando
ℹ️ Link do meu commit relacionado aos passos realizados acima: https://github.com/caiocv18/artigojava/commit/357d95e8b086380b03689eba5e44b9df6db8c036
Adicionando persistência de dados
Nesse momento, será necessário adicionarmos as dependências para a utilização do H2 e do JPA.
Para melhorar o funcionamento inicial, é uma boa ideia utilizar configurações de teste através de dados “mockados”, portanto, será criado um perfil de teste.
1) Inclua as dependências JPA e H2
2) Abrir o arquivo pom.xml
3) Colar as dependências abaixo:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
4) Salvar o arquivo e esperar o Maven baixar as dependências
5) Edite o application.properties
6)Acrescentar as linhas abaixo:
spring.profiles.active=teste
spring.jpa.open-in-view=true
7) Crie o arquivo application-teste.properties
8) Acrescentar as linhas abaixo:
# DATASOURCE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testedb
spring.datasource.username=<seu nome de usuário>
spring.datasource.password=<pode deixar vazio ou colocar uma senha>
# H2 CLIENT
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
# JPA, SQL
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.defer-datasource-initialization=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
⚠️ Não esqueça de substituir os dados de username e password.
ℹ️ Cada informação colocada nesse arquivo será utilizada para se conectar no banco de dados H2.
1) Em entidades/Usuario.java
2) Acrescente @Entity na classe;
ℹ️ Serve para que o JPA estabeleça uma ligação entre a entidade Usuario e a tabela de usuários que será criada no banco H2 quando o sistema for executado.
3) Acrescente @Table(name = "tb_usuario");
ℹ️ Anotação JPA com o intuito de especificar um nome para a tabela que será criada para persistir os dados da entidade em questão.
4) Acrescente @Id acima do id;
ℹ️ Ao utilizar junto da anotação do próximo item, serve para informar qual atributo da entidade será utilizado para representar o Id de cada objeto que também será um registro no banco de dados.
5) Acrescente @GeneratedValue(strategy = GenerationType.IDENTITY);
ℹ️ Especifica de que forma a chave primária deve ser gerada para a tabela e, nesse caso, será gerado através de uma coluna de auto incremento.
6) Altere o id de int para long.
ℹ️ Alteração necessária devido à adição das duas anotações anteriores.
Por fim, através do gif a seguir, veja de que forma é possível acessar o banco H2 depois de executar a aplicação e acessar o endpoint localhost:8080/h2-console:
ℹ️ Link do meu commit relacionado aos passos realizados acima: Criando e se conectando ao banco de dados H20173ea9
Criando o repositório Usuário
Para que seja possível acessarmos o banco e consequentemente acessarmos os dados que serão transferidos para as tabelas, será necessário criar uma interface voltada para isso:
- Crie um pacote repositorios;
- Crie uma interface UsuarioRepositorio;
- Colocar a interface para estender JpaRepository passando o tipo da entidade e o tipo do identificador (Exemplo: JpaRepository<User, Long>).
ℹ️ Não é necessário implementar os métodos pois o JPA Repository já os possui implementados de maneira suficiente para trabalhar com a entidade passada como parâmetro e com a tipagem de identificador utilizada.
Agora, combinando a questão dos dados de teste com a classe de repositório que acabou de ser criada:
1) Crie um pacote chamado config;
2) Crie uma classe chamada TesteConfig;
3) Adicione as anotações @Configuration e @Profile("teste");
4) Crie uma variável do tipo UsuarioRepositorio
ℹ️ Isso acaba causando uma injeção de dependência.
5) Adicione a anotação @Autowired;
ℹ️ Anotação utilizada para apontar uma injeção de dependência usando o Spring.
(O conceito por trás do funcionamento disso daria um artigo separado, mas o intuito aqui é apresentar cada etapa aos poucos). Caso esteja curioso para saber, acesse os seguintes links: - https://medium.com/@leonardogiuliani/autowired-e-a-injeção-de-dependência-do-spring-d8864cc9af50.
OBS: Vá com calma. Caso as explicações te assustem, tenha ciência de que está sendo abordado um conceito avançado e que demanda conhecimentos prévios antes de entender completamente o uso.
6) Implementar a interface CommandLineRunner para que a classe seja executada de maneira automática na inicialização;
7) Sobrescrever o método run da interface, criando usuários para popular o banco de dados:
Usuario usuario1 = new Usuario(null, "Caio", "caio@gmail.com", "988888888", "123456");
Usuario usuario2 = new Usuario(null, "Vinicius", "vinicius@gmail.com", "977777777", "123456");
userRepository.saveAll(Array.asList(usuario1, usuario2));
ℹ️ Retira-se o Id no momento da criação do usuário pois o próprio banco de dados vai se encarregar da geração do número
8) Crie um construtor sem o Id como parâmetro na classe entidades/Usuario.java.
Agora, é possível acessar o console do banco de dados H2 e ver que a tabela criada anteriormente foi populada com os dados de teste que foram acrescentados na classe TesteConfiguracao:
ℹ️ Link do meu commit relacionado aos passos realizados acima: Preenchendo o banco de dados de forma automática2cb76d3
Criando o serviço Usuário
Recapitulando para que serve a camada de serviço, ela é utilizada para que o sistema se comunique de maneira completa com cada funcionalidade do sistema, sendo assim, serão implementadas duas funcionalidades, a de pesquisar todos os registros da tabela e a de pesquisar pelo Id:
1) Criar um pacote servicos
2) Criar uma classe UsuarioServico e colocá-la com a anotação de @Service
package br.com.caiocv18.artigojava.servicos;
import br.com.caiocv18.artigojava.entidades.Usuario;
import br.com.caiocv18.artigojava.repositorios.UsuarioRepositorio;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UsuarioServico {
@Autowired
private UsuarioRepositorio repositorio;
public List<Usuario> pesquisarTodos(){
return repositorio.findAll();
}
public Usuario procurarPorId(Long id){
Optional<Usuario> usuario = repositorio.findById(id);
return usuario.get();
}
}
3) Editar a classe UsuarioRecurso, adicionando uma chamada à função que acabou de ser criada na classe de serviço:
@GetMapping(value = "/{id}") public ResponseEntity<Usuario> procurarTodos(@PathVariable Long id){ Usuario usuario = service.findById(id); return ResponseEntity.ok().body(usuario); }
Sendo assim, ao procurar por um Id utilizando o parâmetro no próprio endpoint como no exemplo abaixo, será possível visualizar cada registro específico da tabela:
ℹ️ Exemplo: localhost:8080/usuarios/1
ℹ️ Link do meu commit relacionado aos passos realizados acima: Pegando os usuários do banco e adicionando a pesquisa por Id82ee17b
Conclusão
Depois de muitos parágrafos, commits, conceitos, da implementação do elemento Usuario em todas as camadas do sistema e de 30 minutos de leitura estimados, é um bom momento para digerir com calma todas as informações que foram apresentadas e checar se realmente foi possível consolidar todos os ensinamentos.
Com toda certeza, o sistema ainda não está pronto, apesar de já ter boas funcionalidades, incluindo a consulta por Id e a persistência no banco de dados utilizando mock.
O artigo com a implementação das demais entidades e os avanços em outras funcionalidades, continua na parte II:
Após a apresentação de tantos conceitos também colocados em prática neste artigo, a parte II terá mais foco no avanço dos demais elementos do sistema, como Despesa, Receita, Categoria e Status.
A parte III estará voltada para a implementação do restante das letras do CRUD, para que seja possível adicionar, atualizar e deletar cada um dos elementos do sistema e de colocar a aplicação em um ambiente hospedado na nuvem utilizando o Heroku.
Agradeço por chegar até aqui e te desejo sucesso nessa nova aventura utilizando Java, Spring, JPA, Hibernate e H2!
Te espero na parte II para continuarmos a implementação do sistema da API de gestão financeira.
Segue meu contato e meu site em caso de alguma dúvida, necessidade ou sugestão:
- caioviniciuscv18@gmail.com
- https://caiocv18.notion.site/
Referências
- Curso do Nélio Alves com diversos projetos utilizando Java disponível na Udemy
Java COMPLETO 2023 Programação Orientada a Objetos +Projetos - Curso de Programação em Java da Universidade de Helsinki
About the course - Java Programming - Guia inicial de Java do Gabriel Reis Duarte disponível na Revelo Community
Guia inicial de Java - O que é um framework
O que é um framework - Primeiros passos com o Spring Boot
Primeiros passos com o Spring Boot - Chat GPT
- Definição de IDE
Ambiente de desenvolvimento integrado - Ícones
Free Icons and Stickers - Millions of images to download - Spring Web Services
Spring Web Services - SOAP
SOAP - ORM - Object Relational Mapping
What is an ORM – The Meaning of Object Relational Mapping Database Tools - Hibernate
O que é e porque devo utilizar o Hibernate? - Diferença Hibernate e JPA
Hibernate e JPA são a mesma coisa?
Como criar um CRUD completo com Hibernate e JPA - Leia aqui - Why does Hibernate require no argument constructor?
Why does Hibernate require no argument constructor? - Serialization in Java - Java Serialization
Serialization in Java - Java Serialization | DigitalOcean - The Spring @Controller and @RestController Annotations
The Spring @Controller and @RestController Annotations | Baeldung - JPA: Como usar a anotação @Entity
JPA: Como usar a anotação @Entity - Qual o objetivo de mocar os dados ? O que isso significa?
Qual o objetivo de mocar os dados ? O que isso significa ? | Fórum Alura - Spring Data JPA – @Table Annotation
Spring Data JPA - @Table Annotation - GeeksforGeeks - ID annotation
ID annotation - JPA: Como usar a anotação @GeneratedValue
JPA: Como usar a anotação @GeneratedValue - Por que (strategy = GenerationType.IDENTITY)?
Por que (strategy = GenerationType.IDENTITY)? | Fórum Alura - Injeção de dependência
Injeção de dependência - Entendendo injeção de dependência
Entendendo injeção de dependência - Autowired e a injeção de dependência do Spring
Autowired e a injeção de dependência do Spring - What Is a Spring Bean?
What Is a Spring Bean? | Baeldung - Introdução prática ao Spring Framework com uso de Anotações
Introdução prática ao Spring Framework com uso de Anotações - Heroku
Cloud Application Platform | Heroku
A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.