diff --git a/README.md b/README.md
index 04995dc..26f7770 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,17 @@
-# Gestión de secretos en distintos entornos (Java + Docker + CI/CD)
+# Configuración de entornos (Java + Docker + CI/CD)
-Este documento resume cómo manejar de manera segura credenciales y secretos en distintos entornos: desarrollo local, Eclipse, Docker, docker-compose y CI/CD (GitHub Actions).
+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).
---
## 1. Desarrollo local (Java)
-Leer secretos usando `System.getenv()`:
+Leer la configuración usando `System.getenv()`:
```java
+String host = System.getenv("DB_HOST");
+String port = System.getenv("DB_PORT");
+String name = System.getenv("DB_NAME");
String user = System.getenv("DB_USER");
String password = System.getenv("DB_PASSWORD");
@@ -21,12 +24,18 @@ if (user == null || password == null) {
**Windows (PowerShell):**
```powershell
+$env:DB_HOST="localhost"
+$env:DB_PORT="3306"
+$env:DB_NAME="mapa_mundi"
$env:DB_USER="mi_usuario"
$env:DB_PASSWORD="mi_password"
```
**Linux / Mac / WSL:**
```bash
+export DB_HOST=localhost
+export DB_PORT=3306
+export DB_NAME=mapa_mundi
export DB_USER=mi_usuario
export DB_PASSWORD=mi_password
```
@@ -39,26 +48,34 @@ export DB_PASSWORD=mi_password
2. Selecciona tu aplicación → pestaña **Environment**
3. Añade las variables:
```
+ Name: DB_HOST Value: localhost
+ Name: DB_PORT Value: 3306
+ Name: DB_NAME Value: mapa_mundi
Name: DB_USER Value: mi_usuario
Name: DB_PASSWORD Value: mi_password
```
4. Apply → Run
-> Esto hace que `System.getenv("DB_USER")` funcione al ejecutar la app desde Eclipse.
+> Esto hace que `System.getenv("DB_HOST")` funcione al ejecutar la app desde Eclipse.
---
## 2. Dockerfile
-Nunca incluir secretos directamente. Solo declarar variables vacÃas como documentación:
+Nunca incluir secretos directamente. Declarar todas las variables vacÃas como documentación:
```dockerfile
-# Documentación de variables esperadas en runtime
+# Configuración (no sensible)
+ENV DB_HOST=""
+ENV DB_PORT=""
+ENV DB_NAME=""
+
+# Secretos
ENV DB_USER=""
ENV DB_PASSWORD=""
```
-> La aplicación sigue leyendo los valores con `System.getenv()` en tiempo de ejecución. Los secretos reales se pasan al contenedor.
+> Los valores reales se pasan al contenedor en tiempo de ejecución. La aplicación los lee con `System.getenv()`.
---
@@ -66,13 +83,25 @@ ENV DB_PASSWORD=""
**Opción A — Variables en lÃnea:**
```bash
-docker run -e DB_USER=mi_usuario -e DB_PASSWORD=mi_password -p 8080:8080 mi-imagen
+docker run \
+ -e DB_HOST=localhost \
+ -e DB_PORT=3306 \
+ -e DB_NAME=mapa_mundi \
+ -e DB_USER=mi_usuario \
+ -e DB_PASSWORD=mi_password \
+ -p 8080:8080 mi-imagen
```
**Opción B — Archivo `.env` (recomendado):**
Archivo `.env`:
```
+# Configuración (no sensible)
+DB_HOST=mysql.vdlp
+DB_PORT=3306
+DB_NAME=mapa_mundi
+
+# Secretos
DB_USER=mi_usuario
DB_PASSWORD=mi_password
```
@@ -89,6 +118,12 @@ docker run --env-file .env -p 8080:8080 mi-imagen
Archivo `.env`:
```
+# Configuración (no sensible)
+DB_HOST=mysql.vdlp
+DB_PORT=3306
+DB_NAME=mapa_mundi
+
+# Secretos
DB_USER=mi_usuario
DB_PASSWORD=mi_password
DB_ROOT_PASSWORD=root
@@ -132,7 +167,10 @@ volumes:
## 5. CI/CD — GitHub Actions
-Definir los secretos en el repositorio: **Settings → Secrets and variables → Actions**.
+Definir en el repositorio (**Settings → Secrets and variables → Actions**):
+
+- **Variables** (no sensibles): `DB_HOST`, `DB_PORT`, `DB_NAME` → en la pestaña *Variables*.
+- **Secretos**: `DB_USER`, `DB_PASSWORD` → en la pestaña *Secrets*.
```yaml
name: Build & Deploy
@@ -151,9 +189,12 @@ jobs:
- name: Build Docker image
run: docker build -t mi-app .
- - name: Run container with secrets
+ - name: Run container
run: |
docker run \
+ -e DB_HOST=${{ vars.DB_HOST }} \
+ -e DB_PORT=${{ vars.DB_PORT }} \
+ -e DB_NAME=${{ vars.DB_NAME }} \
-e DB_USER=${{ secrets.DB_USER }} \
-e DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
mi-app
@@ -168,12 +209,26 @@ jobs:
- No subir `.env` al repositorio.
- No hardcodear credenciales en `config.properties` ni en el código.
- No incluir secretos en la imagen Docker.
-- Documentar las variables necesarias sin poner valores reales (README, Dockerfile vacÃo).
+- Documentar las variables necesarias sin valores reales (README, Dockerfile vacÃo).
+- Separar visualmente configuración y secretos en el `.env`.
- Para producción avanzada: considerar **Secret Manager** (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault).
---
-## 7. Tabla comparativa por entorno
+## 7. Variables: configuración vs secretos
+
+| Variable | Ejemplo | ¿Es secreto? |
+|---|---|---|
+| `DB_HOST` | `mysql.vdlp` | No |
+| `DB_PORT` | `3306` | No |
+| `DB_NAME` | `mapa_mundi` | No |
+| `DB_USER` | `mi_usuario` | SÃ |
+| `DB_PASSWORD` | `mi_password` | SÃ |
+| `DB_ROOT_PASSWORD` | `root` | SÃ |
+
+---
+
+## 8. Tabla comparativa por entorno
| Entorno | Mecanismo | Dónde se definen | ¿Se sube al repo? |
|---|---|---|---|
@@ -182,8 +237,4 @@ jobs:
| Dockerfile | `ENV` (vacÃo) | El propio Dockerfile | SÃ (sin valores) |
| Docker runtime | `-e` / `--env-file` | LÃnea de comandos / `.env` | No |
| Docker Compose | `env_file` | `.env` | No |
-| GitHub Actions | `secrets.*` | Settings del repositorio | No |
-
-
----
-Fuentes: [ChatGPT](https://chat.openai.com) + [Claude](https://claude.ai)
\ No newline at end of file
+| GitHub Actions | `vars.*` / `secrets.*` | Settings del repositorio | No |
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 3dc0b54..8e9a855 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,6 +26,12 @@
spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
org.springframework.boot
diff --git a/src/main/java/org/lapaloma/mapamundi/controller/ContinenteController.java b/src/main/java/org/lapaloma/mapamundi/controller/ContinenteController.java
index d602e82..f66bfdd 100644
--- a/src/main/java/org/lapaloma/mapamundi/controller/ContinenteController.java
+++ b/src/main/java/org/lapaloma/mapamundi/controller/ContinenteController.java
@@ -20,8 +20,13 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api/continentes")
public class ContinenteController {
- private final ContinenteService continenteService = new ContinenteService();
+ private final ContinenteService continenteService;
+ // Spring inyecta automáticamente el service con su DAO
+ public ContinenteController(ContinenteService continenteService) {
+ this.continenteService = continenteService;
+ }
+
// GET /api/continentes - listar todos los continentes
@GetMapping
public List getAll() {
diff --git a/src/main/java/org/lapaloma/mapamundi/dao/impl/ContinenteDaoJDBC.java b/src/main/java/org/lapaloma/mapamundi/dao/impl/ContinenteDaoJDBC.java
index 3e6114b..04f6a4a 100644
--- a/src/main/java/org/lapaloma/mapamundi/dao/impl/ContinenteDaoJDBC.java
+++ b/src/main/java/org/lapaloma/mapamundi/dao/impl/ContinenteDaoJDBC.java
@@ -7,172 +7,181 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
+import javax.sql.DataSource;
+
import org.lapaloma.mapamundi.dao.IContinenteDAO;
-import org.lapaloma.mapamundi.gestores.GestorConexionJDBC;
import org.lapaloma.mapamundi.vo.Continente;
+import org.springframework.stereotype.Repository;
+@Repository
public class ContinenteDaoJDBC implements IContinenteDAO {
+ private final DataSource dataSource;
- @Override
- public Continente obtenerContinentePorClave(String codigo) {
- Continente continente = null;
+ // Spring inyecta el DataSource configurado automáticamente
+ public ContinenteDaoJDBC(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
- String sentenciaSQL = """
- SELECT * FROM T_CONTINENTE
- WHERE codigo=?
- """;
+ @Override
+ public Continente obtenerContinentePorClave(String codigo) {
+ Continente continente = null;
- try (Connection conexion = GestorConexionJDBC.getConexionSGDB();
- PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
+ String sentenciaSQL = """
+ SELECT * FROM T_CONTINENTE
+ WHERE codigo=?
+ """;
- sentenciaJDBCPreparada.setString(1, codigo);
- System.out.println(sentenciaJDBCPreparada);
+ try (Connection conexion = dataSource.getConnection();
+ PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
- ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery();
+ sentenciaJDBCPreparada.setString(1, codigo);
+ System.out.println(sentenciaJDBCPreparada);
- if (resultadoSentencia.next()) {
- continente = getLineaFromResultSet(resultadoSentencia);
- }
+ ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery();
- } catch (Exception e) {
- e.printStackTrace();
- }
+ if (resultadoSentencia.next()) {
+ continente = getLineaFromResultSet(resultadoSentencia);
+ }
- return continente;
- }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
- @Override
- public void actualizarContinente(Continente continente) {
+ return continente;
+ }
- String sentenciaSQL = """
- UPDATE T_CONTINENTE
- SET nombre_continente=?
- WHERE codigo=?
- """;
+ @Override
+ public void actualizarContinente(Continente continente) {
- try (Connection conexion = GestorConexionJDBC.getConexionSGDB();
- PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
+ String sentenciaSQL = """
+ UPDATE T_CONTINENTE
+ SET nombre_continente=?
+ WHERE codigo=?
+ """;
- sentenciaJDBCPreparada.setString(1, continente.getNombre());
- sentenciaJDBCPreparada.setString(2, continente.getCodigo());
+ try (Connection conexion = dataSource.getConnection();
+ PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
- System.out.println(sentenciaJDBCPreparada);
+ sentenciaJDBCPreparada.setString(1, continente.getNombre());
+ sentenciaJDBCPreparada.setString(2, continente.getCodigo());
- sentenciaJDBCPreparada.executeUpdate();
+ System.out.println(sentenciaJDBCPreparada);
- } catch (Exception e) {
- e.printStackTrace();
- }
+ sentenciaJDBCPreparada.executeUpdate();
- }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
- @Override
- public void crearContinente(Continente continente) {
+ }
- String sentenciaSQL = """
- INSERT INTO T_CONTINENTE (codigo, nombre_continente)
- VALUES (?, ?)
- """;
+ @Override
+ public void crearContinente(Continente continente) {
- try (Connection conexion = GestorConexionJDBC.getConexionSGDB();
- PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
+ String sentenciaSQL = """
+ INSERT INTO T_CONTINENTE (codigo, nombre_continente)
+ VALUES (?, ?)
+ """;
- sentenciaJDBCPreparada.setString(1, continente.getCodigo());
- sentenciaJDBCPreparada.setString(2, continente.getNombre());
+ try (Connection conexion = dataSource.getConnection();
+ PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
- System.out.println(sentenciaJDBCPreparada);
+ sentenciaJDBCPreparada.setString(1, continente.getCodigo());
+ sentenciaJDBCPreparada.setString(2, continente.getNombre());
- sentenciaJDBCPreparada.executeUpdate();
+ System.out.println(sentenciaJDBCPreparada);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
+ sentenciaJDBCPreparada.executeUpdate();
- @Override
- public void borrarContinente(Continente continente) {
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
- String sentenciaSQL = """
- DELETE FROM T_CONTINENTE
- WHERE codigo=?
- """;
+ @Override
+ public void borrarContinente(Continente continente) {
- try (Connection conexion = GestorConexionJDBC.getConexionSGDB();
- PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
+ String sentenciaSQL = """
+ DELETE FROM T_CONTINENTE
+ WHERE codigo=?
+ """;
- sentenciaJDBCPreparada.setString(1, continente.getCodigo());
+ try (Connection conexion = dataSource.getConnection();
+ PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
- sentenciaJDBCPreparada.executeUpdate();
+ sentenciaJDBCPreparada.setString(1, continente.getCodigo());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
+ sentenciaJDBCPreparada.executeUpdate();
- @Override
- public List obtenerListaContinentes() {
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
- List lista = new ArrayList<>();
+ @Override
+ public List obtenerListaContinentes() {
- String sentenciaSQL = """
- SELECT * FROM T_CONTINENTE
- """;
+ List lista = new ArrayList<>();
- try (Connection conexion = GestorConexionJDBC.getConexionSGDB();
- PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
+ String sentenciaSQL = """
+ SELECT * FROM T_CONTINENTE
+ """;
- System.out.println(sentenciaJDBCPreparada);
+ try (Connection conexion = dataSource.getConnection();
+ PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
- ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery();
+ System.out.println(sentenciaJDBCPreparada);
- while (resultadoSentencia.next()) {
- lista.add(getLineaFromResultSet(resultadoSentencia));
- }
+ ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery();
- } catch (Exception e) {
- e.printStackTrace();
- }
+ while (resultadoSentencia.next()) {
+ lista.add(getLineaFromResultSet(resultadoSentencia));
+ }
- return lista;
- }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
- @Override
- public List obtenerContinentePorNombre(String nombre) {
+ return lista;
+ }
- List lista = new ArrayList<>();
+ @Override
+ public List obtenerContinentePorNombre(String nombre) {
- String sentenciaSQL = """
- SELECT * FROM T_CONTINENTE
- WHERE nombre_continente LIKE ?
- """;
+ List lista = new ArrayList<>();
- try (Connection conexion = GestorConexionJDBC.getConexionSGDB();
- PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
+ String sentenciaSQL = """
+ SELECT * FROM T_CONTINENTE
+ WHERE nombre_continente LIKE ?
+ """;
- sentenciaJDBCPreparada.setString(1, "%" + nombre + "%");
+ try (Connection conexion = dataSource.getConnection();
+ PreparedStatement sentenciaJDBCPreparada = conexion.prepareStatement(sentenciaSQL);) {
- System.out.println(sentenciaJDBCPreparada);
+ sentenciaJDBCPreparada.setString(1, "%" + nombre + "%");
- ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery();
+ System.out.println(sentenciaJDBCPreparada);
- while (resultadoSentencia.next()) {
- lista.add(getLineaFromResultSet(resultadoSentencia));
- }
+ ResultSet resultadoSentencia = sentenciaJDBCPreparada.executeQuery();
- } catch (Exception e) {
- e.printStackTrace();
- }
+ while (resultadoSentencia.next()) {
+ lista.add(getLineaFromResultSet(resultadoSentencia));
+ }
- return lista;
- }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
- private Continente getLineaFromResultSet(ResultSet resultadoSentencia) throws SQLException {
+ return lista;
+ }
- Continente continente = new Continente();
+ private Continente getLineaFromResultSet(ResultSet resultadoSentencia) throws SQLException {
- continente.setCodigo(resultadoSentencia.getString("codigo"));
- continente.setNombre(resultadoSentencia.getString("nombre_continente"));
+ Continente continente = new Continente();
- return continente;
- }
+ continente.setCodigo(resultadoSentencia.getString("codigo"));
+ continente.setNombre(resultadoSentencia.getString("nombre_continente"));
+
+ return continente;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/lapaloma/mapamundi/gestores/GestorConexionJDBC.java b/src/main/java/org/lapaloma/mapamundi/gestores/GestorConexionJDBC.java
deleted file mode 100644
index c1b6020..0000000
--- a/src/main/java/org/lapaloma/mapamundi/gestores/GestorConexionJDBC.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.lapaloma.mapamundi.gestores;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-
-public class GestorConexionJDBC {
-
- // Evita que pueda construirse un objeto de la clase.
- private GestorConexionJDBC() {
- }
-
- public static Connection getConexionSGDB() throws Exception {
- Connection conexionSGDB = null;
-
- // Datos URL
- String urlBBDD = GestorFicheroConfiguracion.obtenerValor("jdbc.url");
-
- String usuario = System.getenv("DB_USER");
- String contrasenya = System.getenv("DB_PASSWORD");
-
- String claseDriver = GestorFicheroConfiguracion.obtenerValor("jdbc.driver");
- Class.forName(claseDriver);
-
- conexionSGDB = DriverManager.getConnection(urlBBDD, usuario, contrasenya);
-
- return conexionSGDB;
- }
-
-}
diff --git a/src/main/java/org/lapaloma/mapamundi/service/ContinenteService.java b/src/main/java/org/lapaloma/mapamundi/service/ContinenteService.java
index 7305839..50e5aa1 100644
--- a/src/main/java/org/lapaloma/mapamundi/service/ContinenteService.java
+++ b/src/main/java/org/lapaloma/mapamundi/service/ContinenteService.java
@@ -6,14 +6,21 @@ package org.lapaloma.mapamundi.service;
import java.util.List;
import org.lapaloma.mapamundi.dao.IContinenteDAO;
-import org.lapaloma.mapamundi.dao.impl.ContinenteDaoJDBC;
import org.lapaloma.mapamundi.excepcion.ContinenteNoEncontradoException;
import org.lapaloma.mapamundi.vo.Continente;
+import org.springframework.stereotype.Service;
+@Service
public class ContinenteService {
- IContinenteDAO continenteDAO = new ContinenteDaoJDBC();
+ private final IContinenteDAO continenteDAO;
+ // Spring inyecta el DAO automáticamente
+ public ContinenteService(IContinenteDAO continenteDAO) {
+ this.continenteDAO = continenteDAO;
+ }
+
+
public Continente obtenerContinentePorClave(String codigo) {
@@ -23,9 +30,6 @@ public class ContinenteService {
Continente continente = continenteDAO.obtenerContinentePorClave(codigo);
- // Esta lÃnea simula un error de negocio, ignorando lo que devuelve el DAO
- continente = null;
-
if (continente == null) {
throw new ContinenteNoEncontradoException(
@@ -40,6 +44,9 @@ public class ContinenteService {
List lista = continenteDAO.obtenerListaContinentes();
+ // Esto provoca error
+ //lista = null;
+
if (lista == null || lista.isEmpty()) {
throw new RuntimeException("No hay continentes disponibles");
}
@@ -55,6 +62,9 @@ public class ContinenteService {
List lista = continenteDAO.obtenerContinentePorNombre(nombre);
+ // Al comentar este código desaparece el error
+ lista =null;
+
if (lista == null || lista.isEmpty()) {
throw new ContinenteNoEncontradoException(
"No existen continentes con nombre: " + nombre
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..2f3577f
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,8 @@
+spring.datasource.url=${DB_URL}
+spring.datasource.username=${DB_USER}
+spring.datasource.password=${DB_PASSWORD}
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+
+# Opcional: pool
+spring.datasource.hikari.maximum-pool-size=10
+spring.datasource.hikari.minimum-idle=2
\ No newline at end of file
diff --git a/src/main/resources/config.properties b/src/main/resources/config.properties
deleted file mode 100644
index d41c651..0000000
--- a/src/main/resources/config.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-# Parámetros de conexión a la base de datos MapaMundi en SGDB MySQL
-jdbc.driver = com.mysql.cj.jdbc.Driver
-jdbc.url = jdbc:mysql://172.16.0.181:3306/Mapa_Mundi
-
diff --git a/src/test/java/org/lapaloma/mapamundi/service/ContinenteServiceTest.java b/src/test/java/org/lapaloma/mapamundi/service/ContinenteServiceTest.java
index b6d9ea5..e9514f2 100644
--- a/src/test/java/org/lapaloma/mapamundi/service/ContinenteServiceTest.java
+++ b/src/test/java/org/lapaloma/mapamundi/service/ContinenteServiceTest.java
@@ -21,8 +21,7 @@ class ContinenteServiceTest {
@BeforeEach
void setUp() {
fakeDAO = new FakeContinenteDAO();
- continenteService = new ContinenteService();
- continenteService.continenteDAO = fakeDAO;
+ continenteService = new ContinenteService(fakeDAO);
}
// =========================