Construye una API de gestión financiera con Java, Spring Boot, JPA, Hibernate y H2 - Parte I
Este artículo está dirigido a aquéllos que tengan conocimientos intermedios del lenguaje de programación Java, incluyendo también los conceptos y principios de la Programación Orientada a Objetos (POO) y conocimientos conceptuales básicos de SQL.
Para aquellos que son principiantes y entusiastas de los idiomas, recomiendo el contenido de Gabriel Reis Duarte, quien hizo la Guía inicial de Java para quienes se inician en la materia. También recomiendo a los principiantes este curso de la Universidad de Helsinki lleno de ejercicios prácticos: Java Programming.
Este artículo está lleno de referencias. No temas tomarte el tiempo para mirar o leer cada uno de ellos en su totalidad (algunos están en inglés o en portugués).
A lo largo de este artículo, comenzaremos a crear una API REST para la gestión financiera utilizando los siguientes frameworks: Spring, JPA, Hibernate y H2, cada uno con un propósito específico que será presentado más adelante. El sistema tiene como base este diagrama:
No te preocupes por entender el diagrama completo con esta primera imagen: todo se irá mostrará poco a poco a lo largo del artículo.
Debido a la complejidad y profundidad del contenido, este artículo se dividirá en tres, por ello, aquí te dejo el enlace a la segunda y tercera parte (en portugués):
- 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
El proyecto utilizado como base para este artículo se puede encontrar en este repositorio de GitHub.
¿Para qué sirve cada framework?
En primer lugar, es necesario comprender qué es un framework y para qué sirve. En pocas palabras, la traducción literal de “framework” es “marco”. El framework es un conjunto de bibliotecas llenas de funciones, estructuras y métodos que sirven para facilitar el desarrollo de una aplicación. En este caso, se utilizarán diferentes frameworks para facilitar el desarrollo de diferentes partes del sistema.
Spring
Posee varias otras herramientas dentro y, para este artículo, solo se presentarán y utilizarán Spring Boot y Spring Web.
Spring Boot
Spring Boot es responsable de la configuración automática del proyecto, utilizando como base las herramientas de construcción del proyecto Maven o Gradle;
Aquí usaremos Maven, por cierto.
Spring Web
Se utiliza para la creación de servicios de la Web que emplean elprotocolo SOAP. Básicamente, será necesario comunicarse utilizando las reglas de mensajería adoptadas por Internet.
JPA
Se utiliza para que sea posible conservar objetos Java utilizando el ORM en conjunto con la base de datos H2.
Hibernate
También funciona en conjunto con JPA para realizar mapeo de objetos, con el objetivo de conservarlos en la base de datos.
Entonces, ¿cuál sería la diferencia entre Hibernate y JPA? Sería un buen punto de investigación para que tú, el lector, puedas profundizar más adelante, pero, en resumen: JPA es una especificación de Java sobre cómo implementar un ORM e Hibernate es el framework en sí que implementa JPA y proporciona creación, lectura, la actualización y eliminación de objetos persistieron en la base de datos.
H2
Es la base de datos que se utilizará en el proyecto para conservar cada información necesaria en las tablas respectivas. Fue escrita en Java y se eligió por su facilidad de uso. Al ser una base de datos en memoria, no es necesario instalar nada en la computadora. Es una herramienta muy común para realizar pruebas en Java debido a su practicidad.
API de gestión financiera
La API permitirá al usuario informar ingresos y gastos y clasificarlos según categorías creadas por el usuario. Cada categoría o gasto también tendrá un estado.
Proyecto
Este capítulo contiene todos los pasos que involucran el código del proyecto y algunas explicaciones destinadas a explicar las decisiones tomadas.
El proyecto se estructurará en estas capas:
1) Entidad
- Ubicación de todas las clases que definen cada objeto que será utilizado por el sistema. Ejemplos: Usuario, Ingresos, Gastos.
2) Recurso
- Ubicación donde estarán todas las llamadas a la API, responsable de recibir la solicitud y enviar una respuesta.
3) Servicio
- Ubicación de las reglas lógicas que se utilizarán para manejar entidades y acceder a repositorios.
4) Repositorio
- Ubicación donde se utilizará JPA para acceder a los datos que se almacenarán en la base de datos H2.
Creando el proyecto
Para facilitar la creación de proyectos, recomiendo utilizar el sitio web oficial de Spring llamado Spring Initializr para inicializar un proyecto usando Spring Boot.
1) Entra a Spring Initializr;
2) Aquí un ejemplo de rellenado de opciones:
- Project: Maven
- Language: Java
- Spring Boot: 3.0.5 (verificar si hay una opción más reciente)
- Group: br.com.caiocv18 (colocar tu propio sitio de forma invertida)
- Artifact: artigojava (indica el nombre del proyecto)
- Name: artigojava (indica el nombre del proyecto nuevamente)
- Packaging: Jar
- Java: 17
- Dependencies > ADD DEPENDECIES > Spring Web
3) Clic en GENERATE;
4) Descarga el archivo;
5) Descomprime en una carpeta que elijas;
6) Abre IntelliJ o una IDE que prefieras;
7) Abre el proyecto según la carpeta elegida;
8) Ejecuta la aplicación:
9) Ingresar a localhost:8080 en tu navegador;
ℹ️ Link de mi commit relacionado con estos pasos: https://github.com/caiocv18/artigojava/commit/dfb28b7dc68f770a60fc77fc0b0cc6da4af7e9e9
Usuario
Para la clase usuario, tendremos estos atributos:
- id;
- nombre;
- email;
- contraseña.
Con los métodos get y set para cada atributo.
Debido a las anotaciones y funciones que se utilizarán, también es necesario crear los métodos equals y hashCode.
Creando la entidad Usuario
Sigue estos pasos para crear la primera entidad, con el objetivo de seguir la estructura del proyecto presentada anteriormente:
1) Crea un paquete llamado entidades;
2) Crea la clase Usuario;
3) Añade los atributos como private:
- int id;
- String nome;
- String email;
- String senha;
ℹ️ El atributo id será fundamental para utilizar ORM y persistir en la base de datos más tarde.
4) Crea un constructor vacío;
ℹ️ Ese construtor se necesita por el uso del framework Hibernate. Para entender mejor, ve la discusión sobre el tema en Stack Overflow.
5) Crea un constructor con todos los atributos;
6) Genera los getters y setters;
7) Genera hashcode e equals (seleccionar el atributo de ID para hacer la comparación);
8) Implementar la interfaz Serializable;
ℹ️ Serializable sirve para transformar los objetos en cadenas de bytes para que puedan transitar en una red, ser guardados en archivos, etc.
9) Agraga el número de serie patrón sugerido por IntelliJ para Serializable.
Creando el recurso Usuario
1) Crea un paquete de recursos
2) Crea una clase UsuarioRecurso
3) Agrega la anotación @RestController encima de la clase
ℹ️ Controlador necesario para manipular la clase en cuestión y serializar el objeto generado para que sea posible enviarlo y recibirlo en la web.
4) Añade la anotación debajo de la anterior para @RequestMapping, pasando como parámetro (value = "/usuarios")
5) Crea un método con base en la tipado ResponseEntity<T> donde el tipo de entidad se pasaen lugar de T: ResponseEntity<Usuario>
public ResponseEntity<Usuario> findAll{
}
6) Devolver un nuevo objeto, solo para probar.
Usuario novoUsuario = new Usuario(1, "Caio", "caiocv18_dev@gmail.com","6199999999","12345")
return ResponseEntity.ok().body(u);
7) Agrega anotación para el tipo de requisición del método, colocando la Annotation @GetMapping
8) La clase queda de la siguiente 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);
}
}
Al final, será posible acceder a [localhost:8080/usuarios](<http://localhost:8080/usuarios>) y visualizar el usuario del que se creó una instancia en el ejemplo anterior:
ℹ️ Link de mi commit sobre estos pasos: https://github.com/caiocv18/artigojava/commit/357d95e8b086380b03689eba5e44b9df6db8c036
Agregando persistencia de datos
En este punto, necesitaremos agregar dependencias para usar H2 y JPA.
Para mejorar la operación inicial, es una buena idea utilizar configuraciones de prueba a través de datos simulados, por lo que se creará un perfil de prueba.
1) Incluye las dependencias JPA y H2
2) Abrir el archivo pom.xml
3) Pega las dependencias abajo:
<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) Guarda el archivo y espera que Maven baje las dependencias
5) Edita application.properties
6) Añade las líneas siguientes:
spring.profiles.active=teste
spring.jpa.open-in-view=true
7) Crea el archivo application-teste.properties
8) Inserta:
# 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
⚠️ No olvide reemplazar tu nombre de usuario y contraseña.
ℹ️ Cada información colocada en este archivo se utilizará para conectarse a la base de datos H2.
1) Ve a entidades/Usuario.java
2) Inserta @Entity en la clase;
ℹ️ Se utiliza para que JPA establezca un vínculo entre la entidad Usuario y la tabla de usuarios que se creará en la base de datos H2 cuando se ejecute el sistema.
3) Inserta @Table(name = "tb_usuario");
ℹ️ Anotación JPA para especificar un nombre para la tabla que se creará para conservar los datos de la entidad en cuestión.
4) Inserta @Id encima del id;
ℹ️ Cuando se usa junto con la anotación del siguiente elemento, sirve para informar qué atributo de la entidad se usará para representar el Id de cada objeto, que también será un registro en la base de datos.
5) Inserta @GeneratedValue(strategy = GenerationType.IDENTITY);
ℹ️ Especifica cómo se debe generar la clave principal para la tabla y, en este caso, se generará a través de una columna de incremento automático.
6) Altera el id de int por long.
ℹ️ Cambio necesario debido a la adición de las anotaciones anteriores.
Finalmente, con el siguiente gif verás cómo es posible acceder a la base de datos H2 después de ejecutar la aplicación y acceder al punto final localhost:8080/h2-console:
ℹ️ Link de mi commit sobre el tema: Criando e se conectando ao banco de dados H20173ea9
Creando el repositorio Usuario
Para poder acceder a la base de datos y en consecuencia acceder a los datos que serán transferidos a las tablas, será necesario crear una interfaz orientada a esto:
- Crea un paquete repositorios;
- Crea una interfaz UsuarioRepositorio;
- Coloca la interfaz para extender JpaRepository pasando el tipo de la entidade e identificador (ejemplo: JpaRepository<User, Long>).
ℹ️ No es necesario implementar los métodos ya que el Repositorio JPA ya los tiene suficientemente implementados para trabajar con la entidad pasada como parámetro y con el tipo de identificador utilizado.
Ahora, combinando el problema de los datos de prueba con la clase de repositorio que se acaba de crear:
1) Crea un paquete llamado config;
2) Crea una clase llamada TesteConfig;
3) Agrega las anotaciones @Configuration y @Profile("teste");
4) Crea una variable de tipo UsuarioRepositorio
ℹ️ Eso causa una inyección de dependencia.
5) Agrega la anotación @Autowired;
ℹ️ Anotación utilizada para señalar una inyección de dependencia usando Spring.
(El concepto detrás de cómo funciona esto sería un artículo aparte, pero la intención aquí es presentar cada paso poco a poco). Si tienes curiosidad por saberlo, visita: https://medium.com/@leonardogiuliani/autowired-e-a-injeção-de-dependência-do-spring-d8864cc9af50.
NOTA: Va con calma. Si las explicaciones te asustan, ten en cuenta que se está tratando un concepto avanzado y que requiere conocimientos previos antes de comprender plenamente su uso.
6) Implementa la interfaz CommandLineRunner para que la clase se ejecute de manera automática en la inicialización;
7) Sobreescribe el método run de la interfaz, creando usuarios para llenar la base de datos:
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));
ℹ️ El Id se elimina cuando se crea el usuario porque la propia base de datos será la encargada de generar el número.
8) Crea un constructor sin el Id como parámetro en la clase entidades/Usuario.java.
Ahora es posible acceder a la consola de la base de datos H2 y ver que la tabla creada anteriormente se llenó con los datos de prueba que se agregaron a la clase PruebaConfiguracion:
ℹ️ Link de mi commit relacionado: Preenchendo o banco de dados de forma automática2cb76d3
Creando el servicio Usuario
Recapitulando, la capa de servicio sirve para que el sistema se comunique completamente con cada funcionalidad del sistema. Por lo tanto, se implementarán dos funcionalidades, la de buscar todos los registros de la tabla y la de buscar por Id:
1) Crear un paquete llamado servicios
2) Crear una clase UsuarioServicio y colocarla con la anotación 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 la clase UsuarioRecurso, añadiendo un llamado a la función que acaba de ser creada en la clase de servicio:
@GetMapping(value = "/{id}") public ResponseEntity<Usuario> procurarTodos(@PathVariable Long id){ Usuario usuario = service.findById(id); return ResponseEntity.ok().body(usuario); }
Por lo tanto, al buscar un Id utilizando el parámetro en el propio endpoint como en el ejemplo siguiente, será posible ver cada registro específico en la tabla:
ℹ️ Ejemplo: localhost:8080/usuarios/1
ℹ️ Link de mi commit relacionado: Pegando os usuários do banco e adicionando a pesquisa por Id82ee17b
Conclusión
Después de muchos párrafos, commits, conceptos, la implementación del elemento Usuario en todas las capas del sistema y un estimado de 30 minutos de lectura, es un buen momento para digerir con calma toda la información que se presentó y comprobar si realmente fue posible consolidar todas las enseñanzas.
Ciertamente, el sistema aún no está listo, a pesar de que ya tiene buenas características, incluida la consulta por ID y la persistencia en la base de datos mediante simulacros.
El artículo con la implementación de otras entidades y avances en otras funcionalidades continúa en la parte II (en portugués):
Después de presentar tantos conceptos que también se ponen en práctica en este artículo, la parte II se centrará más en avanzar en los otros elementos del sistema, como Gastos, Ingresos, Categoría y Estado.
La parte III se centrará en implementar el resto de las letras CRUD, de modo que sea posible agregar, actualizar y eliminar cada uno de los elementos del sistema y colocar la aplicación en un entorno alojado en la nube utilizando Heroku.
¡Gracias por llegar hasta aquí y te deseo éxito en esta nueva aventura usando Java, Spring, JPA, Hibernate y H2!
Los espero en la parte II para que podamos seguir implementando el sistema API de gestión financiera.
Si tienes dudas, contáctame:
- caioviniciuscv18@gmail.com
- https://caiocv18.notion.site/
Referencias
- Curso de Nélio Alves con diversos proyectos utilizando Java, disponible en Udemy
Java COMPLETO 2023 Programação Orientada a Objetos +Projetos - Curso de Programación en Java de la Universidad de Helsinki
About the course - Java Programming - Guía inicial de Java de Gabriel Reis Duarte, disponible en Listopro Community.
Guía inicial de Java - Qué es un framework
O que é um framework - Primeros pasos con Spring Boot
Primeros pasos con Spring Boot - Chat GPT
- Definición de IDE
Ambiente de desarrollo integrado - Íconos
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
¿Qué es y por qué debo utilizar Hibernate? - Diferencia entre Hibernate y JPA
Hibernate y JPA: ¿son lo mismo?
Cómo crear un CRUD completo con Hibernate y JPA - 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: Cómo usar la anotación @Entity
JPA: Cómo usar la anotación @Entity - ¿Cuál es el objetivo de "mockar" los datos? ¿Qué significa?
¿Cuál es el objetivo de "mockar" los datos? ¿Qué significa? - Spring Data JPA – @Table Annotation
Spring Data JPA - @Table Annotation - GeeksforGeeks - ID annotation
ID annotation - JPA: Cómo usar la anotación @GeneratedValue
JPA: Cómo usar la anotación @GeneratedValue - Por qué (strategy = GenerationType.IDENTITY)?
Por qué (strategy = GenerationType.IDENTITY)? | Fórum Alura - Injección de dependencia
Injección de dependencia - Entendiendo inyección de dependencia
Entendiendo inyección de dependencia - Autowired y la inyección de dependencia de Spring
Autowired y la inyección de dependencia de Spring - What Is a Spring Bean?
What Is a Spring Bean? | Baeldung - Introducción prcática a Spring Framework con anotaciones
Introducción práctica a Spring Framework con anotaciones - Heroku
Cloud Application Platform | Heroku
Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.