From 1130791dcfefd7c9837b37b5088bdacb26c1828c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isidoro=20Nevares=20Mart=C3=ADn?= Date: Sun, 12 Apr 2026 12:07:01 +0200 Subject: [PATCH] Commit inicial --- .gitignore | 7 + README.md | 4 + pom.xml | 66 +++++++ .../org/lapaloma/hogwarts/AppHogwartsSB.java | 14 ++ .../hogwarts/controller/CasaController.java | 53 +++++ .../org/lapaloma/hogwarts/dao/ICasaDAO.java | 19 ++ .../hogwarts/dao/impl/CasaDaoJDBC.java | 186 ++++++++++++++++++ .../excepcion/CasaNoEncontradaException.java | 12 ++ .../hogwarts/service/CasaService.java | 76 +++++++ .../java/org/lapaloma/mapamundi/vo/Casa.java | 50 +++++ src/main/resources/application.properties | 13 ++ .../hogwarts/service/CasaServiceTest.java | 165 ++++++++++++++++ 12 files changed, 665 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/org/lapaloma/hogwarts/AppHogwartsSB.java create mode 100644 src/main/java/org/lapaloma/hogwarts/controller/CasaController.java create mode 100644 src/main/java/org/lapaloma/hogwarts/dao/ICasaDAO.java create mode 100644 src/main/java/org/lapaloma/hogwarts/dao/impl/CasaDaoJDBC.java create mode 100644 src/main/java/org/lapaloma/hogwarts/excepcion/CasaNoEncontradaException.java create mode 100644 src/main/java/org/lapaloma/hogwarts/service/CasaService.java create mode 100644 src/main/java/org/lapaloma/mapamundi/vo/Casa.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/org/lapaloma/hogwarts/service/CasaServiceTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0293886 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/bin/ +*.class +/target/ +# Eclipse +.classpath +.project +.settings/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a57d2b5 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Repositorio para el examen de Ampliación de Entornos de 3ª Evaluación. + +Este documento resume cómo gestionar la configuración y los secretos de una aplicación en distintos entornos: desarrollo local, Eclipse, Docker, docker-compose y CI/CD (GitHub Actions). + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..76e54b2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + org.lapaloma.mapamundi + aaee_mapamundi + 0.0.2 + + Prueba de Springboot + Proyecto para poder probar el funcionamiento de SpringBoot + + + org.springframework.boot + spring-boot-starter-parent + 4.0.1 + + + + UTF-8 + 23 + 6.0.3 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + com.mysql + mysql-connector-j + runtime + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/lapaloma/hogwarts/AppHogwartsSB.java b/src/main/java/org/lapaloma/hogwarts/AppHogwartsSB.java new file mode 100644 index 0000000..b2607bf --- /dev/null +++ b/src/main/java/org/lapaloma/hogwarts/AppHogwartsSB.java @@ -0,0 +1,14 @@ +package org.lapaloma.hogwarts; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AppHogwartsSB { + + public static void main(String[] args) { + SpringApplication.run(AppHogwartsSB.class, args); + + } + +} \ No newline at end of file diff --git a/src/main/java/org/lapaloma/hogwarts/controller/CasaController.java b/src/main/java/org/lapaloma/hogwarts/controller/CasaController.java new file mode 100644 index 0000000..9e2e63f --- /dev/null +++ b/src/main/java/org/lapaloma/hogwarts/controller/CasaController.java @@ -0,0 +1,53 @@ +/** + * + */ +package org.lapaloma.hogwarts.controller; + +import java.util.List; + +import org.lapaloma.hogwarts.service.CasaService; +import org.lapaloma.mapamundi.vo.Casa; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Isidoro Nevares Martín - Virgen de la Paloma Fecha creación: 13 mar 2026 + */ +@RestController +@RequestMapping("/hogwarts/casas") +public class CasaController { + + private final CasaService casaService; + + // Spring inyecta automáticamente el service con su DAO + public CasaController(CasaService casaService) { + this.casaService = casaService; + } + + // GET /hogwarts/casas - listar todos las casas + @GetMapping + public List getAll() { + List listaCasas = casaService.obtenerListaCasas(); + return listaCasas; + } + + // GET /hogwarts/casas/id/{id} - Obtener un Casa por su código + @GetMapping("/id/{id}") + public ResponseEntity getByCodigo(@PathVariable("id") Integer identificador) { + Casa Casa = casaService.obtenerCasaPorClave(identificador); + + return Casa != null ? ResponseEntity.ok(Casa) : ResponseEntity.notFound().build(); + } + + // GET /hogwarts/casas/nombre/{nombre} - Obtener un Casa por su nombre + @GetMapping("/nombre/{nombre}") + public List getByNombre(@PathVariable("nombre") String nombre) { + List listaCasas = casaService.obtenerCasaPorNombre(nombre); + + return listaCasas; + } + +} diff --git a/src/main/java/org/lapaloma/hogwarts/dao/ICasaDAO.java b/src/main/java/org/lapaloma/hogwarts/dao/ICasaDAO.java new file mode 100644 index 0000000..91692d6 --- /dev/null +++ b/src/main/java/org/lapaloma/hogwarts/dao/ICasaDAO.java @@ -0,0 +1,19 @@ +package org.lapaloma.hogwarts.dao; + +import java.util.List; + +import org.lapaloma.mapamundi.vo.Casa; + +public interface ICasaDAO { + public Casa obtenerCasaPorClave(int identificador); + + public void actualizarCasa(Casa Casa); + + public void crearCasa(Casa Casa); + + public void borrarCasa(Casa Casa); + + public List obtenerListaCasas(); + + public List obtenerCasaPorNombre(String nombre); +} diff --git a/src/main/java/org/lapaloma/hogwarts/dao/impl/CasaDaoJDBC.java b/src/main/java/org/lapaloma/hogwarts/dao/impl/CasaDaoJDBC.java new file mode 100644 index 0000000..6188756 --- /dev/null +++ b/src/main/java/org/lapaloma/hogwarts/dao/impl/CasaDaoJDBC.java @@ -0,0 +1,186 @@ +package org.lapaloma.hogwarts.dao.impl; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import javax.sql.DataSource; + +import org.lapaloma.hogwarts.dao.ICasaDAO; +import org.lapaloma.mapamundi.vo.Casa; +import org.springframework.stereotype.Repository; + +@Repository +public class CasaDaoJDBC implements ICasaDAO { + private final DataSource dataSource; + + // Spring inyecta el DataSource configurado automáticamente + public CasaDaoJDBC(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public Casa obtenerCasaPorClave(int identificador) { + Casa Casa = null; + + String sentenciaSQL = """ + SELECT * FROM casa + WHERE idCasa =? + """; + + try (Connection conexion = dataSource.getConnection(); + PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) { + + sentenciaJDBCPreparada.setInt(1, identificador); + System.out.println(sentenciaJDBCPreparada); + + ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery(); + + if (resultadoSentencia.next()) { + Casa = getLineaFromResultSet(resultadoSentencia); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return Casa; + } + + @Override + public void actualizarCasa(Casa Casa) { + + String sentenciaSQL = """ + UPDATE casa + SET Nombre=? + WHERE idCasa=? + """; + + try (Connection conexion = dataSource.getConnection(); + PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) { + + sentenciaJDBCPreparada.setString(1, Casa.getNombre()); + sentenciaJDBCPreparada.setInt(2, Casa.getIdentificador()); + + System.out.println(sentenciaJDBCPreparada); + + sentenciaJDBCPreparada.executeUpdate(); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public void crearCasa(Casa Casa) { + + String sentenciaSQL = """ + INSERT INTO casa (idCasa, Nombre) + VALUES (?, ?) + """; + + try (Connection conexion = dataSource.getConnection(); + PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) { + + sentenciaJDBCPreparada.setInt(1, Casa.getIdentificador()); + sentenciaJDBCPreparada.setString(2, Casa.getNombre()); + + System.out.println(sentenciaJDBCPreparada); + + sentenciaJDBCPreparada.executeUpdate(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void borrarCasa(Casa Casa) { + + String sentenciaSQL = """ + DELETE FROM casa + WHERE idCasa=? + """; + + try (Connection conexion = dataSource.getConnection(); + PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) { + + sentenciaJDBCPreparada.setInt(1, Casa.getIdentificador()); + sentenciaJDBCPreparada.executeUpdate(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public List obtenerListaCasas() { + + List lista = new ArrayList<>(); + + String sentenciaSQL = """ + SELECT * FROM casa + """; + + try (Connection conexion = dataSource.getConnection(); + PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) { + + System.out.println(sentenciaJDBCPreparada); + + ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery(); + + while (resultadoSentencia.next()) { + lista.add(getLineaFromResultSet(resultadoSentencia)); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return lista; + } + + @Override + public List obtenerCasaPorNombre(String nombre) { + + List lista = new ArrayList<>(); + + String sentenciaSQL = """ + SELECT * FROM casa + WHERE Nombre LIKE ? + """; + + try (Connection conexion = dataSource.getConnection(); + PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) { + + sentenciaJDBCPreparada.setString(1, "%" + nombre + "%"); + + System.out.println(sentenciaJDBCPreparada); + + ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery(); + + while (resultadoSentencia.next()) { + lista.add(getLineaFromResultSet(resultadoSentencia)); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return lista; + } + + private Casa getLineaFromResultSet(ResultSet resultadoSentencia) throws SQLException { + + Casa Casa = new Casa(); + + Casa.setIdentificador(resultadoSentencia.getInt("idCasa")); + Casa.setNombre(resultadoSentencia.getString("Nombre")); + + return Casa; + } +} \ No newline at end of file diff --git a/src/main/java/org/lapaloma/hogwarts/excepcion/CasaNoEncontradaException.java b/src/main/java/org/lapaloma/hogwarts/excepcion/CasaNoEncontradaException.java new file mode 100644 index 0000000..d907103 --- /dev/null +++ b/src/main/java/org/lapaloma/hogwarts/excepcion/CasaNoEncontradaException.java @@ -0,0 +1,12 @@ +package org.lapaloma.hogwarts.excepcion; + +public class CasaNoEncontradaException extends RuntimeException { + /** + * + */ + private static final long serialVersionUID = -3344627619585104664L; + + public CasaNoEncontradaException(String mensaje) { + super(mensaje); + } +} diff --git a/src/main/java/org/lapaloma/hogwarts/service/CasaService.java b/src/main/java/org/lapaloma/hogwarts/service/CasaService.java new file mode 100644 index 0000000..725e3bd --- /dev/null +++ b/src/main/java/org/lapaloma/hogwarts/service/CasaService.java @@ -0,0 +1,76 @@ +/** + * + */ +package org.lapaloma.hogwarts.service; + +import java.util.List; + +import org.lapaloma.hogwarts.dao.ICasaDAO; +import org.lapaloma.hogwarts.excepcion.CasaNoEncontradaException; +import org.lapaloma.mapamundi.vo.Casa; +import org.springframework.stereotype.Service; + +@Service +public class CasaService { + + private final ICasaDAO casaDAO; + + // Spring inyecta el DAO automáticamente + public CasaService(ICasaDAO casaDAO) { + this.casaDAO = casaDAO; + } + + + public Casa obtenerCasaPorClave(Integer identificador) { + + + if (identificador == null || identificador <= 0) { + throw new IllegalArgumentException("Código inválido"); + } + + Casa Casa = casaDAO.obtenerCasaPorClave(identificador); + + + if (Casa == null) { + throw new CasaNoEncontradaException( + "No existe una casa con idenficador: " + identificador + ); + } + + return Casa; + } + + public List obtenerListaCasas() { + + List lista = casaDAO.obtenerListaCasas(); + + // Esto provoca error + lista = null; + + if (lista == null || lista.isEmpty()) { + throw new RuntimeException("No hay casas disponibles"); + } + + return lista; + } + + public List obtenerCasaPorNombre(String nombre) { + + if (nombre == null || nombre.isBlank()) { + throw new IllegalArgumentException("Nombre inválido"); + } + + List lista = casaDAO.obtenerCasaPorNombre(nombre); + + // Esto provoca error s + lista =null; + + if (lista == null || lista.isEmpty()) { + throw new CasaNoEncontradaException( + "No existen casas con nombre: " + nombre + ); + } + + return lista; + } +} \ No newline at end of file diff --git a/src/main/java/org/lapaloma/mapamundi/vo/Casa.java b/src/main/java/org/lapaloma/mapamundi/vo/Casa.java new file mode 100644 index 0000000..93c0efe --- /dev/null +++ b/src/main/java/org/lapaloma/mapamundi/vo/Casa.java @@ -0,0 +1,50 @@ +package org.lapaloma.mapamundi.vo; + +/** + * + * Casa: Clase de persistencia que representa una Casa de Hogwarts. + * + * @author Isidoro Nevares Martín - IES Virgen de la Paloma + * @date 03 marzo 2026 + * + * + */ +public class Casa { + private int identificador; + private String nombre; + + /** + * @param identificador + * @param nombre + */ + public Casa(int identificador, String nombre) { + super(); + this.identificador = identificador; + this.nombre = nombre; + } + + public Casa() { + } + + public int getIdentificador() { + return identificador; + } + + public void setIdentificador(int identificador) { + this.identificador = identificador; + } + + public String getNombre() { + return nombre; + } + + public void setNombre(String nombre) { + this.nombre = nombre; + } + + @Override + public String toString() { + return "Casa [identificador=" + identificador + ", nombre=" + nombre + "]"; + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..14f89a4 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,13 @@ +# Puerto en que escucha Spring Boot +server.port=8080 + +# Servicio de la base de datos. +# Ejemplo url base dator: +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.url=jdbc:mysql://${DB_HOST:192.168.1.36}:${DB_PORT:3306}/${DB_NAME:Hogwarts} +spring.datasource.username=${DB_USER:root} +spring.datasource.password=${DB_PASSWORD:mysql_123} + +# Parámetros del Pool de conexiones HikariCP +spring.datasource.hikari.maximum-pool-size=10 +spring.datasource.hikari.minimum-idle=2 \ No newline at end of file diff --git a/src/test/java/org/lapaloma/hogwarts/service/CasaServiceTest.java b/src/test/java/org/lapaloma/hogwarts/service/CasaServiceTest.java new file mode 100644 index 0000000..c6ad003 --- /dev/null +++ b/src/test/java/org/lapaloma/hogwarts/service/CasaServiceTest.java @@ -0,0 +1,165 @@ +package org.lapaloma.hogwarts.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.lapaloma.hogwarts.dao.ICasaDAO; +import org.lapaloma.hogwarts.excepcion.CasaNoEncontradaException; +import org.lapaloma.mapamundi.vo.Casa; + +class CasaServiceTest { + + private CasaService casaService; + private FakeCasaDAO fakeDAO; + + @BeforeEach + void setUp() { + fakeDAO = new FakeCasaDAO(); + casaService = new CasaService(fakeDAO); + } + + // ========================= + // obtenerCasaPorClave + // ========================= + + @Test + void obtenerCasaPorClave_cuandoCodigoEsNull_lanzaExcepcion() { + assertThrows(IllegalArgumentException.class, () -> { + casaService.obtenerCasaPorClave(null); + }); + } + + @Test + void obtenerCasaPorClave_cuandoCodigoEstaVacio_lanzaExcepcion() { + assertThrows(IllegalArgumentException.class, () -> { + casaService.obtenerCasaPorClave(0); + }); + } + + @Test + void obtenerCasaPorClave_cuandoNoExiste_lanzaExcepcion() { + assertThrows(CasaNoEncontradaException.class, () -> { + casaService.obtenerCasaPorClave(99); + }); + } + + @Test + void obtenerCasaPorClave_cuandoExiste_retornaCasa() { + fakeDAO.crearCasa(new Casa(2, "Slytherin")); + + Casa resultado = casaService.obtenerCasaPorClave(2); + + assertNotNull(resultado); + assertEquals("Europa", resultado.getNombre()); + } + + // ========================= + // obtenerListaCasas + // ========================= + + @Test + void obtenerListaCasas_cuandoListaEstaVacia_lanzaExcepcion() { + assertThrows(RuntimeException.class, () -> { + casaService.obtenerListaCasas(); + }); + } + + @Test + void obtenerListaCasas_cuandoHayDatos_retornaLista() { + fakeDAO.crearCasa(new Casa(2, "Slytherin")); + + List resultado = casaService.obtenerListaCasas(); + + assertNotNull(resultado); + assertEquals(1, resultado.size()); + } + + // ========================= + // obtenerCasaPorNombre + // ========================= + + @Test + void obtenerCasaPorNombre_cuandoNombreEsNull_lanzaExcepcion() { + assertThrows(IllegalArgumentException.class, () -> { + casaService.obtenerCasaPorNombre(null); + }); + } + + @Test + void obtenerCasaPorNombre_cuandoNombreEstaVacio_lanzaExcepcion() { + assertThrows(IllegalArgumentException.class, () -> { + casaService.obtenerCasaPorNombre(""); + }); + } + + @Test + void obtenerCasaPorNombre_cuandoNoExiste_lanzaExcepcion() { + assertThrows(CasaNoEncontradaException.class, () -> { + casaService.obtenerCasaPorNombre("Inexistente"); + }); + } + + @Test + void obtenerCasaPorNombre_cuandoExiste_retornaLista() { + fakeDAO.crearCasa(new Casa(2, "Slytherin")); + + List resultado = casaService.obtenerCasaPorNombre("Slytherin"); + + assertEquals(1, resultado.size()); + } + + // ========================= + // Fake DAO. Se crea el DAO dentro del test para no depender de la conexión a la base de datos, de si hay red, de si accede a un fichero... + // En caso de usar el DOA real (CasaDaoJDBC) estaríamos hablando de prubeas de integración. + // ========================= + + static class FakeCasaDAO implements ICasaDAO { + + private List data = new ArrayList<>(); + + @Override + public Casa obtenerCasaPorClave(int identificador) { + return data.stream() + .filter(c -> c.getIdentificador()==identificador) + .findFirst() + .orElse(null); + } + + @Override + public List obtenerListaCasas() { + return new ArrayList<>(data); + } + + @Override + public List obtenerCasaPorNombre(String nombre) { + List resultado = new ArrayList<>(); + + for (Casa c : data) { + if (c.getNombre().equals(nombre)) { + resultado.add(c); + } + } + return resultado; + } + + @Override + public void actualizarCasa(Casa Casa) { + } + + @Override + public void crearCasa(Casa Casa) { + data.add(Casa); + } + + @Override + public void borrarCasa(Casa Casa) { + + } + } +} \ No newline at end of file