Introducción
En este artículo vamos a crear una aplicación con Spring Boot, MySQL, JPA y además utilizando contenedores.
A continuación, para este ejemplo utilizaremos Docker para crear y ejecutar la imagen de la aplicación como un contenedor Docker.
Por lo tanto diseñaremos una solución de gestión de usuarios, para realizar ingresos y consultas en la base de datos.
Requisitos
Lenguaje de programación | Java SE 11 | Oracle: https://www.oracle.com/java/technologies/javase-jdk11-downloads.html |
Entorno Integrado de Desarrollo (IDE) | Intellij | https://www.jetbrains.com/idea/download/ |
Base de Datos | MySQL | |
Docker | Docker | https://www.docker.com/get-started |
Postman | Postman | https://www.postman.com/ |
Creación de la aplicación en Spring Boot
Ingresamos al sitio web https://start.spring.io/ para esta demo. Creamos un proyecto con Maven, en lenguaje seleccionamos Java. Continuamos para seleccionar la versión de Spring boot, para esta demo escogemos la version estable 2.2.6. En el paso siguiente diligenciamos los datos del proyecto, donde definiremos nuestro ID de grupo que también se convertirá en un paquete base en nuestro proyecto Java. En el campo Artefacto, definiremos el ID del artefacto, que también será el nombre de nuestro proyecto.
Por último seleccionamos las Dependencias que se utilizaran en la demo, para este ejemplo seleccionamos las siguientes dependencias Spring Data JPA, Spring Web Starter y MySQL Driver. Una de las ventajas de Spring Boot es que proporciona paquetes iniciales que simplifica su configuración de Maven. Los iniciadores Spring Boot son en realidad un conjunto de dependencias que puede incluir en su proyecto. Puede escribir las dependencias en el campo de búsqueda o cambiar a la versión completa y ver todos los paquetes de inicio y las dependencias disponibles como se puede observar en la figura 1.
Figura 1
Estructura de la Aplicación
Como se puede observar la figura 2, la estructura de la aplicación estará divida por paquete.
Figura 2
El archivo pom.xml contiene toda la información básica sobre el proyecto, como pueden observar en este archivo, podemos adicionar las dependencias, configurar los datos, los plugins y las propiedades del proyecto.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example.jugnicaragua</groupId> <artifactId>jugnicaragua</artifactId> <version>1.0.0</version> <name>jugnicaragua</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <finalName>demo-nica</finalName> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build> </project>
Una breve explicación de las clases o interfaces que se utilizarán en el ejemplo.
Person.java
Esta clase de modelo representa una persona. Contiene un id de persona que se auto-genera, con sus respectivo nombre y apellido, como se puede observar la figura 3.
package com.example.jugnicaragua.jugnicaragua.model; import javax.persistence.*; @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="idperson") private Long idPerson; @Column(name="firstname", nullable = false, length=70) private String firstName; @Column(name="lastname", nullable = false, length=70) private String lastName; public Long getIdPerson() { return idPerson; } public void setIdPerson(Long idPerson) { this.idPerson = idPerson; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
Figura 3
IPersonDAO.java
El Spring Boot Data JPA proporciona una interfaz CrudRepository para dar soporte a las operaciones básicas de las operaciones CRUD, dándole funcionalidades a la clase entidad, como se puede observar la figura 4.
package com.example.jugnicaragua.jugnicaragua.dao; import com.example.jugnicaragua.jugnicaragua.model.Person; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface IPersonDAO extends CrudRepository<Person, Long> { }
Figura 4
PersonaService.java
La clase de PersonaService facilita la comunicación del repositorio con las operaciones de guardar, actualizar, eliminar, listar por IdPersona y listar todas las personas, como se puede observar la figura 5.
package com.example.jugnicaragua.jugnicaragua.service; import com.example.jugnicaragua.jugnicaragua.dao.IPersonDAO; import com.example.jugnicaragua.jugnicaragua.model.Person; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class PersonService { @Autowired private IPersonDAO dao; public Person save(Person t) { return dao.save(t); } public Person update(Person t) { return dao.save(t); } public void delete(Person t) { dao.delete(t); } public Iterable<Person> list() { return dao.findAll(); } public Optional<Person> listId(long id) { return dao.findById(id); } }
Figura 5
PersonController.java
Los servicios web son aplicaciones que se comunican a través de Internet utilizando el protocolo HTTP. Hay muchos tipos diferentes de arquitecturas de servicios web, pero la idea principal en todos los diseños es la misma. En este artículo estamos creando un servicio web RESTful a partir de lo que es un diseño, con el objetivo de ver la información de una persona. crear endpoint permite crear un nuevo registro de la persona en el sistema. También existe la opción de un endpoint, donde devuelve una respuesta JSON donde se visualiza la información de todas las personas disponibles en la aplicación, ver/{id} endpoint permite buscar información de la persona con el id de persona apropiada, como se puede observar la figura 6.
package com.example.jugnicaragua.jugnicaragua.controller; import com.example.jugnicaragua.jugnicaragua.exception.ModelNotFoundException; import com.example.jugnicaragua.jugnicaragua.model.Person; import com.example.jugnicaragua.jugnicaragua.service.PersonService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.Optional; @RestController public class PersonController { @Autowired PersonService personService; @PostMapping("/save") public long save(@RequestBody Person person) { personService.save(person); return person.getIdPerson(); } @GetMapping("/listAll") public Iterable<Person> listAllPersons() { return personService.list(); } @GetMapping("/list/{id}") public Person listPersonById(@PathVariable("id") int id) { Optional<Person> person = personService.listId(id); if(person.isPresent()) { return person.get(); } throw new ModelNotFoundException("Invalid find person provided"); } }
Figura 6
ModelNotFoundException.java
Lanzará una excepción de tiempo de ejecución personalizada si el identificador de la persona no existe en la aplicación, como se puede observar la figura 7.
package com.example.jugnicaragua.jugnicaragua.exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.NOT_FOUND) public class ModelNotFoundException extends RuntimeException { public ModelNotFoundException(String mensaje) { super(mensaje); } }
Figura 7
Application.properties
Spring Boot application.properties nos permite configurar la aplicación Spring Boot como se puede observar en la figura 8. Nuestra aplicación se ejecutará en el puerto 8089 conectado a una base de datos MySQL con nombre de usuario sa y contraseña sa.
server.port=8089 spring.datasource.url=jdbc:mysql://mysql-standalone:3306/jugnicaragua spring.datasource.username=sa spring.datasource.password=sa spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
Figura 8
Crear la imagen Docker
Creamos un nuevo archivo con el nombre Dockerfile dentro de la carpeta jugnicaragua al mismo nivel que se encuentran la carpeta src, con las instrucciones que se muestran en la figura 9. Esto es con el objetivo de construir una imagen con la versión de Java y el ejecutable de la aplicación.
FROM openjdk:11 ADD target/demo-nica.jar demo-nica.jar EXPOSE 8089 ENTRYPOINT ["java", "-jar", "demo-nica.jar"]
Figura 9
- openJDK 11.
- Adicionamos en el directorio target el jar de la demo en este caso se llama demo-nica.
- En esta línea se configura el puerto de la aplicación lo colocamos el 8089.
- Ejecutamos el comando Java -Jar.
Desplegar la Aplicación
Creamos la Imagen Docker, usando el siguiente comando desde el directorio donde se encuentra el archivo Docker. Este comando instruye a Docker para crear la imagen de nuestra aplicación. Como se puede observar la figura 10, fueron creadas exitosamente las imágenes.
sudo docker build -t demo-nica .
Figura 10
Si quieren verificar las imágenes creadas utilizamos el siguiente comando, y el resultado será como se puede observar en la figura 11.
docker images
Figura 11
En el siguiente paso ejecutamos el comando, con el objetivo desplegar en la máquina un contenedor docker de MySql.
sudo docker pull mysql:5.7
Para este caso, seleccionamos la versión de MySQL y podemos usar el comando de arriba. De esta manera, podemos pull de la imagen mysql-server:5.7, como se puede observar en la figura 12.
Figura 12
Desplegar el contenedor
Para desplegar el servidor de MySQL podemos usar el siguiente comando, para que funcione como un contenedor Docker.
sudo docker run --name mysql-standalone -e MYSQL_ROOT_PASSWORD=sa -e MYSQL_DATABASE=jugnicaragua -e MYSQL_USER=sa -e MYSQL_PASSWORD=sa -d mysql:5.7
Verificamos los registros de inicio de MySQL usando el siguiente comando:
docker container logs mysql-standalone
Para conectarnos al contenedor mysql, ejecutamos el siguiente comandos:
docker exec -it mysql-standalone bash -l
(Donde mysql-standalone es el nombre que se colocó al contenedor)
iniciamos sesion en MySQL con el siguiente comando, como se puede observar en la figura 13
mysql -usa -psa
Figura 13
Para verificar si está creada la base de datos JUGNicaragua, utilizamos el siguiente comando show databases; como se puede observar en la figura 14.
Figura 14
Desplegar el contenedor de la Aplicación
Ejecutamos nuestra aplicación Sprint Boot, usando los siguientes comandos:
1) mvn clean package 2) mvn compile 3) mvn install 4) docker run -d -p 8089:8089 --name demo-nica --link mysql-standanole:mysql demo-nica
Verificamos los registros de inicio del contenedor de la aplicación, usando el siguiente comando:
docker container logs demo-nica
Nota: En el caso que requieran eliminar los contenedores o imágenes de docker.
Eliminar todos los contenedores
docker rm -vf $(docker ps -a -q)
Eliminar todos las imágene
docker rmi -f $(docker images -a -q)
Ejecutar en POSTMAN
Crear un nuevo registro
Crear una nueva solicitud POST para crear un nuev registro de persona. Una vez que el rgsitro se crea con éxito, obtenemos el ID de la persona como respuesta. Como se puede observar en la figura 15
Figura 15
Ver todas las personas registradas
Es una operación GET devuelve todas las personas registrada en la aplicación, Como se puede observar en la figura 16
Figura 16
Repositorio
Puedes descargar el código de la aplicación desde aquí:
Conclusión
Se desarrolló una aplicación en spring boot para desplegarla por medio de un contenedor docker y conectada con una base de datos MySQL. Para la personas que quieran seguir aprendiendo pueden agregar la parte de eliminar y actualizar persona.
Referencias
- https://stackoverflow.com/questions/44785585/how-to-delete-all-docker-local-docker-images
- https://medium.com/codefountain/develop-a-spring-boot-and-mysql-application-and-run-in-docker-end-to-end-15b7cdf3a2ba
- https://mkyong.com/docker/docker-spring-boot-examples/
- http://geovanny0401.blogspot.com/2018/08/construir-una-aplicacion-web-con-vaadin.html