diff --git a/010_spring_boot/api_rest/api/pom.xml b/010_spring_boot/api_rest/api/pom.xml
index 2240b31..dcad58c 100644
--- a/010_spring_boot/api_rest/api/pom.xml
+++ b/010_spring_boot/api_rest/api/pom.xml
@@ -38,6 +38,31 @@
spring-boot-starter-test
test
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.flywaydb
+ flyway-core
+
+
+ org.flywaydb
+ flyway-mysql
+
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/controller/MedicoController.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/controller/MedicoController.java
index 69bb17a..d24e904 100644
--- a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/controller/MedicoController.java
+++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/controller/MedicoController.java
@@ -1,15 +1,23 @@
package med.voll.api.controller;
+import jakarta.validation.Valid;
import med.voll.api.medico.DatosRegistroMedico;
+import med.voll.api.medico.Medico;
+import med.voll.api.medico.MedicoRepository;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/medicos")
public class MedicoController {
+ // No es recomendable usar @Autowired a nivel de declaración pues genera
+ // problemas al realizar pruebas unitarias
+ @Autowired
+ private MedicoRepository medicoRepository;
@PostMapping
- public void registrarMedico(@RequestBody DatosRegistroMedico datosRegistroMedico) {
- System.out.println(datosRegistroMedico);
+ public void registrarMedico(@RequestBody @Valid DatosRegistroMedico datosRegistroMedico) {
+ medicoRepository.save(new Medico(datosRegistroMedico));
}
}
diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/DatosDireccion.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/DatosDireccion.java
index 892015c..0b3a6ea 100644
--- a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/DatosDireccion.java
+++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/DatosDireccion.java
@@ -1,4 +1,11 @@
package med.voll.api.direccion;
-public record DatosDireccion(String calle, String distrito, String cuidad, String numero, String complemento) {
+import jakarta.validation.constraints.NotBlank;
+
+public record DatosDireccion(
+ @NotBlank String calle,
+ @NotBlank String distrito,
+ @NotBlank String ciudad,
+ String numero,
+ String complemento) {
}
diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/Direccion.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/Direccion.java
new file mode 100644
index 0000000..23488c7
--- /dev/null
+++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/direccion/Direccion.java
@@ -0,0 +1,27 @@
+package med.voll.api.direccion;
+
+import jakarta.persistence.Embeddable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Embeddable
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class Direccion {
+
+ private String calle;
+ private String numero;
+ private String complemento;
+ private String distrito;
+ private String ciudad;
+
+ public Direccion(DatosDireccion direccion) {
+ this.calle = direccion.calle();
+ this.numero = direccion.numero();
+ this.complemento = direccion.complemento();
+ this.distrito = direccion.distrito();
+ this.ciudad = direccion.ciudad();
+ }
+}
diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java
index 0c22109..78ee8e2 100644
--- a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java
+++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java
@@ -1,8 +1,17 @@
package med.voll.api.medico;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
import med.voll.api.direccion.DatosDireccion;
-public record DatosRegistroMedico(String nombre, String email, String documento,
- Especialidad especialidad, DatosDireccion direccion) {
-
-}
+public record DatosRegistroMedico(
+ @NotBlank String nombre,
+ @NotBlank @Email String email,
+ @NotBlank String telefono,
+ @NotBlank @Pattern(regexp = "\\d{4,6}") String documento,
+ @NotNull Especialidad especialidad,
+ @NotNull @Valid DatosDireccion direccion
+) {}
diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/Medico.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/Medico.java
new file mode 100644
index 0000000..3df02fb
--- /dev/null
+++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/Medico.java
@@ -0,0 +1,38 @@
+package med.voll.api.medico;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import med.voll.api.direccion.Direccion;
+
+@Table(name="medicos")
+@Entity(name="Medico")
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(of = "id")
+public class Medico {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+ private String nombre;
+ private String email;
+ private String telefono;
+ private String documento;
+ @Enumerated
+ private Especialidad especialidad;
+ @Embedded
+ private Direccion direccion;
+
+ public Medico(DatosRegistroMedico datosRegistroMedico) {
+ this.nombre = datosRegistroMedico.nombre();
+ this.email = datosRegistroMedico.email();
+ this.telefono = datosRegistroMedico.telefono();
+ this.documento = datosRegistroMedico.documento();
+ this.especialidad = datosRegistroMedico.especialidad();
+ this.direccion = new Direccion(datosRegistroMedico.direccion());
+ }
+}
diff --git a/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/MedicoRepository.java b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/MedicoRepository.java
new file mode 100644
index 0000000..dfe4532
--- /dev/null
+++ b/010_spring_boot/api_rest/api/src/main/java/med/voll/api/medico/MedicoRepository.java
@@ -0,0 +1,5 @@
+package med.voll.api.medico;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface MedicoRepository extends JpaRepository {}
diff --git a/010_spring_boot/api_rest/api/src/main/resources/application.properties b/010_spring_boot/api_rest/api/src/main/resources/application.properties
index 8b13789..0794eec 100644
--- a/010_spring_boot/api_rest/api/src/main/resources/application.properties
+++ b/010_spring_boot/api_rest/api/src/main/resources/application.properties
@@ -1 +1,3 @@
-
+spring.datasource.url=jdbc:mysql://192.168.0.8/vollmed_api
+spring.datasource.username=alura
+spring.datasource.password=alura
\ No newline at end of file
diff --git a/010_spring_boot/api_rest/api/src/main/resources/db/migration/V1__create-table-medicos.sql b/010_spring_boot/api_rest/api/src/main/resources/db/migration/V1__create-table-medicos.sql
new file mode 100644
index 0000000..a7e0bb8
--- /dev/null
+++ b/010_spring_boot/api_rest/api/src/main/resources/db/migration/V1__create-table-medicos.sql
@@ -0,0 +1,16 @@
+create table medicos(
+
+ id bigint not null auto_increment,
+ nombre varchar(100) not null,
+ email varchar(100) not null unique,
+ documento varchar(6) not null unique,
+ especialidad varchar(100) not null,
+ calle varchar(100) not null,
+ distrito varchar(100) not null,
+ complemento varchar(100),
+ numero varchar(20),
+ ciudad varchar(100) not null,
+
+ primary key(id)
+
+);
\ No newline at end of file
diff --git a/010_spring_boot/api_rest/api/src/main/resources/db/migration/V2__alter-table-medicos-add-telefono.sql b/010_spring_boot/api_rest/api/src/main/resources/db/migration/V2__alter-table-medicos-add-telefono.sql
new file mode 100644
index 0000000..0da717e
--- /dev/null
+++ b/010_spring_boot/api_rest/api/src/main/resources/db/migration/V2__alter-table-medicos-add-telefono.sql
@@ -0,0 +1 @@
+alter table medicos add telefono varchar(20) not null;
\ No newline at end of file
diff --git a/010_spring_boot/spring_boot_1.md b/010_spring_boot/spring_boot_1.md
index 3c5c9e0..a32dde5 100644
--- a/010_spring_boot/spring_boot_1.md
+++ b/010_spring_boot/spring_boot_1.md
@@ -156,9 +156,9 @@ Representación en formato **JSON**
```json
{
- “nombre” : “Mochila”,
- “precio” : 89.90,
- “descripcion” : “Mochila para notebooks de hasta 17 pulgadas”
+ "nombre" : "Mochila",
+ "precio" : 89.90,
+ "descripcion" : "Mochila para notebooks de hasta 17 pulgadas"
}
```
@@ -315,10 +315,10 @@ public final class Telefono {
}
```
-Con **Record** todo ese código se puede resumir en una sola línea:
+Con **Record** el código anterior se resume en una sola línea:
```java
-public record Telefono(String ddd, String numero){}
+public record Telefono(String ddd, String numero) {}
```
Internamente, Java transforma este registro en una clase inmutable, muy similar
@@ -327,3 +327,192 @@ al código que se muestra arriba.
Documentación Java
[record](https://docs.oracle.com/en/java/javase/17/language/records.html)
+
+## Agregando dependencias
+
+Copiar `xml` de Spring [initializr](https://start.spring.io/), y pegar en `pom.xml`
+
+Modificar `resources/application.properties`
+
+```ini
+spring.datasource.url=jdbc:mysql:///vollmed-api
+spring.datasource.username=
+spring.datasource.password=
+```
+
+Recomendaciones [12 Factor App](https://12factor.net/es/), que define las 12
+mejores prácticas para crear aplicaciones modernas, escalables y de mantenimiento
+sencillo.
+
+En algunos proyectos Java, dependiendo de la tecnología elegida, es común
+encontrar clases que siguen el patrón DAO, usado para aislar el acceso a los
+datos. Sin embargo, en este curso usaremos otro patrón, conocido como
+***Repositorio***.
+
+***¿cuál es la diferencia entre los dos enfoques y por qué esta elección?***
+
+#### Patrón DAO
+
+El patrón de diseño DAO, también conocido como **Data Access Object**, se
+utiliza para la persistencia de datos, donde su objetivo principal es separar
+las reglas de negocio de las reglas de acceso a la base de datos. En las clases
+que siguen este patrón, aislamos todos los códigos que se ocupan de conexiones,
+comandos SQL y funciones directas a la base de datos, para que dichos códigos
+no se esparzan a otras partes de la aplicación, algo que puede dificultar el
+mantenimiento del código y también el intercambio de tecnologías y del mecanismo
+de persistencia.
+
+Implementación
+Supongamos que tenemos una tabla de productos en nuestra base de datos. La
+implementación del ***patrón DAO*** sería la sgte:
+
+Primero, será necesario crear una clase básica de dominio Producto:
+
+```java
+public class Producto {
+ private Long id;
+ private String nombre;
+ private BigDecimal precio;
+ private String descripcion;
+
+ // constructores, getters y setters
+}
+```
+
+A continuación, necesitaríamos crear la clase ProductoDao, que proporciona
+operaciones de persistencia para la clase de dominio Producto:
+
+```java
+public class ProductoDao {
+
+ private final EntityManager entityManager;
+
+ public ProductoDao(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ }
+
+ public void create(Producto producto) {
+ entityManager.persist(producto);
+ }
+
+ public Producto read(Long id) {
+ return entityManager.find(Producto.class, id);
+ }
+
+ public void update(Producto producto) {
+ entityManger.merge(producto);
+ }
+
+ public void remove(Producto producto) {
+ entityManger.remove(producto);
+ }
+
+}
+```
+
+En el ejemplo anterior, se utilizó JPA como tecnología de persistencia de datos
+de la aplicación.
+
+**Patrón Repository**. Según el famoso libro Domain-Driven Design de Eric Evans:
+
+El repositorio es un mecanismo para encapsular el almacenamiento, recuperación y
+comportamiento de búsqueda, que emula una colección de objetos.
+
+En pocas palabras, un repositorio también maneja datos y oculta consultas
+similares a DAO. Sin embargo, se encuentra en un nivel más alto, más cerca de
+la lógica de negocio de una aplicación. Un repositorio está vinculado a la
+regla de negocio de la aplicación y está asociado con el agregado de sus objetos
+de negocio, devolviéndolos cuando es necesario.
+
+Pero debemos estar atentos, porque al igual que en el patrón DAO, las reglas de
+negocio que están involucradas con el procesamiento de información no deben estar
+presentes en los repositorios. Los repositorios no deben tener la responsabilidad
+de tomar decisiones, aplicar algoritmos de transformación de datos o brindar
+servicios directamente a otras capas o módulos de la aplicación. Mapear entidades
+de dominio y proporcionar funcionalidades de aplicación son responsabilidades muy
+diferentes.
+
+Un repositorio se encuentra entre las reglas de negocio y la capa de persistencia:
+
+1. Proporciona una interfaz para las reglas comerciales donde se accede a los
+objetos como una colección.
+2. Utiliza la capa de persistencia para escribir y recuperar datos necesarios
+para persistir y recuperar objetos de negocio.
+
+Por lo tanto, incluso es posible utilizar uno o más DAOs en un repositorio.
+
+***¿Por qué el patrón repositorio en lugar de DAO usando Spring?***
+
+El patrón de repositorio fomenta un diseño orientado al dominio, lo que
+proporciona una comprensión más sencilla del dominio y la estructura de datos.
+Además, al usar el repositorio de Spring, no tenemos que preocuparnos por usar
+la API de JPA directamente, simplemente creando los métodos, que Spring crea la
+implementación en tiempo de ejecución, lo que hace que el código sea mucho más
+simple, pequeño y legible.
+
+### Validaciones
+
+Bean Validation se compone de varias ***anotaciones*** que se deben agregar a los
+atributos en los que queremos realizar las validaciones. Se implementaron algunas
+de estas anotaciones, como **`@NotBlank`**, que indica que un atributo String no
+puede ser nulo o vacío. (
+[DatosRegistroMedico.java](./api_rest/api/src/main/java/med/voll/api/medico/DatosRegistroMedico.java)
+)
+
+Sin embargo, existen decenas de otras anotaciones que se pueden utilizar, para
+los más diversos tipos de atributos.
+
+Se puede consultar una lista de las principales anotaciones de **Bean Validation**
+en la
+[documentación oficial](https://jakarta.ee/specifications/bean-validation/3.0/jakarta-bean-validation-spec-3.0.html#builtinconstraints).
+
+### Migraciones
+
+Estas se crean en el directorio
+[/src/db/migration/](./api_rest/api/src/main/resources/db/migration/). Es
+importante detener siempre el proyecto al crear los archivos de migración, para
+evitar que **Flyway** los ejecute antes de tiempo, con el código aún incompleto,
+lo que podría causar problemas.
+
+En caso de:
+
+```sql
+# Soft
+DELETE FROM flyway_schema_history WHERE success = 0;
+
+# Hard
+DROP TABLE flyway_schema_history;
+```
+
+### Lombok
+
+Es una biblioteca de Java especialmente enfocada en la reducción de código y
+en la productividad en el desarrollo de proyectos.
+
+Utiliza la idea de ***anotaciones*** para generar códigos en el tiempo de
+compilación. Pero el código generado no es visible, y tampoco es posible cambiar
+lo que se ha generado.
+
+Puede ser una buena herramienta aliada a la hora de escribir clases complejas,
+siempre que el desarrollador tenga conocimiento sobre ella. Para más información
+ver la documentación de [Lombok](https://projectlombok.org/)
+
+### Anotacion Autowired
+
+En el contexto del framework Spring, que utiliza como una de sus bases el patrón
+de diseño *"Inyección de Dependencias"*, la idea sirve para definir una
+inyección automática en un determinado componente del proyecto Spring, ese
+componente puede ser atributos, métodos e incluso constructores.
+
+Esta anotación se permite por el uso de la anotación `@SpringBootApplication`,
+en el archivo de configuración de Spring, disponible cada vez que se crea un
+proyecto Spring.
+
+Al marcar un componente con la anotación `@Autowired` le estamos diciendo a
+Spring que el componente es un punto donde se debe inyectar una dependencia,
+en otras palabras, el componente se inyecta en la clase que lo posee,
+estableciendo una colaboración entre componentes.
+
+Para más información sobre la anotación, ver la
+[documentación oficial](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html)
+