Llega el momento de escribir código. En esta lección generarás el proyecto ciclourbana con Spring Initializr —tanto desde la web como desde la línea de comandos—, lo abrirás en tu IDE y crearás el primer endpoint real de la plataforma: GET /api/v1/estaciones, que devolverá la lista de estaciones de la red de Ribalta. Después lo ejecutarás de tres maneras distintas, lo probarás con curl y lo empaquetarás en un JAR ejecutable que se ejecuta con java -jar sin instalar ningún servidor. Al terminar tendrás una API funcionando de principio a fin.
Contenido
- Spring Initializr: qué es y cómo se usa
- Generar el proyecto desde la web
- Generar el proyecto desde la línea de comandos
- Importar el proyecto en el IDE
- La clase de arranque generada
- El primer endpoint:
GET /api/v1/estaciones - Ejecutar la aplicación
- Probar el endpoint con curl
- Empaquetar y ejecutar el JAR
- Spring Boot DevTools y el reinicio automático
- Errores Comunes y Consejos
- Ejercicios
- Spring Initializr: qué es y cómo se usa
Spring Initializr (start.spring.io) es el generador oficial de proyectos Spring Boot. Le indicas cuatro datos y una lista de dependencias, y te devuelve un ZIP con:
- Un
pom.xmlya configurado con el parent de Spring Boot y las dependencias elegidas. - La clase principal de la aplicación, anotada y lista para arrancar.
- Una clase de prueba básica.
- El wrapper de Maven (
mvnw,mvnw.cmd,.mvn/). - Un
.gitignoreadecuado y unapplication.propertiesvacío.
Es la forma correcta de empezar cualquier proyecto Spring Boot. Crear la estructura a mano es posible, pero es trabajo innecesario y propenso a errores.
- Generar el proyecto desde la web
Abre https://start.spring.io y rellena el formulario con estos valores exactos, que usaremos durante todo el curso:
| Campo | Valor | Por qué |
|---|---|---|
| Project | Maven | Decidido en la lección 01-02 |
| Language | Java | — |
| Spring Boot | La última 3.x estable ofrecida | Evita las versiones marcadas SNAPSHOT o M1 (preliminares) |
| Group | com.ciclourbana |
Identifica a la organización |
| Artifact | ciclourbana |
Nombre del proyecto y del JAR |
| Name | ciclourbana |
Genera la clase CiclourbanaApplication |
| Description | Gestión de la red de bicicletas eléctricas de Ribalta |
Metadato del pom.xml |
| Package name | com.ciclourbana |
Importante: el paquete raíz del proyecto |
| Packaging | Jar | JAR ejecutable con servidor embebido |
| Java | 21 | Versión LTS del curso |
En el panel Dependencies, pulsa "ADD DEPENDENCIES" y añade exactamente dos:
- Spring Web — Spring MVC, Jackson para JSON y Tomcat embebido. Es lo que convierte el proyecto en una aplicación web.
- Spring Boot DevTools — reinicio automático al cambiar código y desactivación de cachés en desarrollo.
Pulsa GENERATE. Se descarga ciclourbana.zip. Descomprímelo donde guardes tus proyectos.
Un consejo antes de descargar: el botón EXPLORE muestra el contenido del proyecto sin bajarlo, y SHARE genera una URL que reproduce exactamente esa configuración. Es muy útil para compartir el punto de partida con un compañero.
- Generar el proyecto desde la línea de comandos
Spring Initializr también es una API HTTP. Esto permite generar el proyecto sin abrir el navegador, y —más importante— dejar el comando guardado en la documentación del equipo para que cualquiera reproduzca el mismo punto de partida.
curl https://start.spring.io/starter.zip \
-d type=maven-project \
-d language=java \
-d bootVersion=3.3.5 \
-d groupId=com.ciclourbana \
-d artifactId=ciclourbana \
-d name=ciclourbana \
-d description="Gestion de la red de bicicletas electricas de Ribalta" \
-d packageName=com.ciclourbana \
-d packaging=jar \
-d javaVersion=21 \
-d dependencies=web,devtools \
-o ciclourbana.zip
# Descomprimir en una carpeta con el nombre del proyecto
unzip ciclourbana.zip -d ciclourbana
cd ciclourbanaDesglose de las opciones de curl:
-d clave=valorenvía un parámetro de formulario. Al usar-d, curl hace automáticamente una petición POST.dependencies=web,devtoolses la lista de identificadores de dependencias separados por comas.webcorresponde a "Spring Web" ydevtoolsa "Spring Boot DevTools".-o ciclourbana.zipguarda la respuesta en un fichero en vez de volcarla a la terminal.
Dos comandos exploratorios muy útiles:
# Ver toda la configuración disponible: versiones, dependencias e identificadores
curl https://start.spring.io
# Consultar los metadatos en JSON (versiones de Boot disponibles, etc.)
curl -H "Accept: application/json" https://start.spring.io | head -40Si omites bootVersion, Initializr usa la última estable, que es lo habitualmente deseable.
- Importar el proyecto en el IDE
El proyecto es un proyecto Maven estándar, así que cualquier IDE lo entiende.
IntelliJ IDEA: File → Open y selecciona la carpeta ciclourbana (no el pom.xml suelto, aunque también funciona). IntelliJ detecta el pom.xml, indexa el proyecto y descarga las dependencias. Verás una barra de progreso abajo a la derecha; espera a que termine.
Eclipse / STS: File → Import → Maven → Existing Maven Projects, selecciona la carpeta raíz y pulsa Finish.
VS Code: File → Open Folder sobre ciclourbana. La extensión de Java arranca sola y aparece un panel Spring Boot Dashboard en la barra lateral.
En los tres casos, la primera importación tarda: Maven descarga las dependencias de Spring a ~/.m2/repository. Son unos cientos de megabytes la primera vez y prácticamente instantáneo a partir de entonces.
- La clase de arranque generada
Abre src/main/java/com/ciclourbana/CiclourbanaApplication.java. Contiene esto:
package com.ciclourbana;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CiclourbanaApplication {
public static void main(String[] args) {
SpringApplication.run(CiclourbanaApplication.class, args);
}
}Son diez líneas, pero cada una importa:
@SpringBootApplicationes la anotación que lo activa todo. Agrupa tres anotaciones que estudiaremos en el módulo 2: habilita la autoconfiguración, marca la clase como fuente de configuración y activa el escaneo de componentes a partir de este paquete.maines un métodomainde Java corriente. Una aplicación Spring Boot es, literalmente, un programa Java que arranca por sumain. No hay contenedor externo que la invoque.SpringApplication.run(...)crea el contexto de Spring, registra los beans y —al detectar Spring Web— arranca Tomcat. Devuelve el contexto ya en marcha. Lo que ocurre dentro, paso a paso, es el tema de la lección 01-05.- El argumento
argsse propaga: permite pasar parámetros desde la línea de comandos, como--server.port=9090.
Por coherencia con el resto del curso, renombra la clase a CicloUrbanaApplication (con la U mayúscula). Usa la función de renombrado del IDE (Shift+F6 en IntelliJ) para que actualice también el fichero de prueba.
- El primer endpoint:
GET /api/v1/estaciones
GET /api/v1/estacionesVamos a exponer las estaciones de Ribalta. Necesitamos dos piezas: un tipo que represente una estación y un controlador que la devuelva en JSON.
El record Estacion
Java 21 ofrece los records, ideales para datos inmutables. Crea el fichero src/main/java/com/ciclourbana/estaciones/Estacion.java:
package com.ciclourbana.estaciones;
/**
* Representa una estación de anclaje de la red de Ribalta.
* De momento es un simple record en memoria; en el módulo 4
* se convertirá en una entidad JPA persistida en base de datos.
*/
public record Estacion(
Long id,
String nombre,
String direccion,
int capacidad,
double latitud,
double longitud
) {
}Por qué un record y no una clase normal:
- Genera automáticamente el constructor, los métodos de acceso (
nombre(),capacidad()...),equals,hashCodeytoString. - Es inmutable: una vez creado no cambia, lo que evita errores en entornos concurrentes.
- Jackson, la librería que Spring Boot usa para convertir objetos a JSON, entiende los records desde hace varias versiones. Cada componente se convierte en una propiedad JSON con el mismo nombre.
El controlador
Crea src/main/java/com/ciclourbana/estaciones/EstacionController.java:
package com.ciclourbana.estaciones;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/v1/estaciones")
public class EstacionController {
// Datos fijos en memoria. En el módulo 4 vendrán de PostgreSQL.
private static final List<Estacion> ESTACIONES = List.of(
new Estacion(1L, "Plaza Mayor", "Plaza Mayor, 1", 24, 40.4168, -3.7038),
new Estacion(2L, "Estación Norte", "Avenida de la Estación 3", 30, 40.4290, -3.7020),
new Estacion(3L, "Parque del Río", "Paseo Fluvial 12", 18, 40.4105, -3.6950),
new Estacion(4L, "Universidad", "Campus Sur, acceso B", 36, 40.4402, -3.7255)
);
@GetMapping
public List<Estacion> listarEstaciones() {
return ESTACIONES;
}
}Qué hace cada anotación, en su nivel justo para esta lección:
@RestControllermarca la clase como componente de Spring que atiende peticiones HTTP y cuyos métodos devuelven directamente el cuerpo de la respuesta (no el nombre de una vista HTML). Spring detecta la clase al escanear el paquete y la registra.@RequestMapping("/api/v1/estaciones")fija la ruta base de todos los métodos de la clase. Así el prefijo se escribe una sola vez.@GetMappingsin argumentos asocia el método aGETsobre la ruta base exacta, es decirGET /api/v1/estaciones.- El método devuelve un
List<Estacion>. Spring Boot, gracias a Jackson, lo convierte automáticamente a un array JSON y fija la cabeceraContent-Type: application/json. No hay que serializar nada a mano.
El detalle de estas anotaciones, la negociación de contenido, los códigos de estado y el manejo de parámetros se tratan en profundidad en el módulo 3. Aquí nos basta con que funcione.
Cómo encajan las piezas
sequenceDiagram
participant C as curl
participant T as Tomcat embebido
participant D as DispatcherServlet
participant E as EstacionController
participant J as Jackson
C->>T: GET /api/v1/estaciones
T->>D: Petición HTTP
D->>D: Buscar el método que atiende la ruta
D->>E: listarEstaciones()
E-->>D: Lista de Estacion
D->>J: Serializar a JSON
J-->>D: Array JSON de estaciones
D-->>T: 200 OK + cuerpo JSON
T-->>C: Respuesta HTTP
- Ejecutar la aplicación
Hay tres formas, y conviene conocer las tres.
Con el plugin de Maven
Es la forma canónica desde la terminal:
spring-boot:run compila el proyecto y arranca la aplicación en la misma JVM que Maven, sin necesidad de empaquetar. Es lo más cómodo durante el desarrollo.
La salida termina con algo parecido a:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
2026-08-31T10:22:41.118+02:00 INFO 18422 --- [ciclourbana] [ restartedMain] c.c.CicloUrbanaApplication : Starting CicloUrbanaApplication using Java 21.0.5
2026-08-31T10:22:42.905+02:00 INFO 18422 --- [ciclourbana] [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2026-08-31T10:22:42.918+02:00 INFO 18422 --- [ciclourbana] [ restartedMain] c.c.CicloUrbanaApplication : Started CicloUrbanaApplication in 2.174 secondsLas tres líneas clave: la versión de Java usada, el puerto 8080 en el que escucha Tomcat y el tiempo de arranque. Interpretaremos este log línea a línea en la lección 01-05.
Para detener la aplicación, Ctrl+C.
Desde el IDE
Abre CicloUrbanaApplication y ejecuta el método main como cualquier programa Java: el triángulo verde en IntelliJ, Run As → Java Application en Eclipse, o Run sobre el main en VS Code.
La ventaja del IDE es el depurador: puedes poner un punto de interrupción en listarEstaciones() y ver la ejecución detenerse cuando llegue la petición.
STS y VS Code ofrecen además un Spring Boot Dashboard para arrancar, parar y reiniciar sin buscar la clase.
Desde el JAR empaquetado
Es la forma de producción, y la vemos en el apartado 9.
- Probar el endpoint con curl
Con la aplicación en marcha, abre otra terminal:
Respuesta:
[{"id":1,"nombre":"Plaza Mayor","direccion":"Plaza Mayor, 1","capacidad":24,"latitud":40.4168,"longitud":-3.7038},{"id":2,"nombre":"Estación Norte",...}]Para verlo legible y con las cabeceras:
# Con cabeceras y código de estado
curl -i http://localhost:8080/api/v1/estaciones
# Formateado con jq (si lo tienes instalado)
curl -s http://localhost:8080/api/v1/estaciones | jqLa respuesta con -i empieza así:
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 31 Aug 2026 08:24:11 GMTObserva que no has escrito una sola línea sobre JSON ni sobre el código 200. Spring Boot ha deducido el Content-Type a partir del tipo de retorno y ha aplicado el 200 por defecto. Esa es la autoconfiguración trabajando.
Prueba también una ruta inexistente para ver el comportamiento por defecto ante errores:
curl -i http://localhost:8080/api/v1/bicicletas
# HTTP/1.1 404
# {"timestamp":"...","status":404,"error":"Not Found","path":"/api/v1/bicicletas"}Spring Boot devuelve un cuerpo de error estructurado sin que hayas configurado nada. Personalizarlo es el objetivo de la lección 03-06.
- Empaquetar y ejecutar el JAR
Construir el artefacto
Este comando limpia la carpeta target, compila, ejecuta las pruebas y genera el JAR. Al terminar:
ls -lh target/*.jar
# -rw-r--r-- 1 usuario usuario 22M ciclourbana-0.0.1-SNAPSHOT.jar
# -rw-r--r-- 1 usuario usuario 12K ciclourbana-0.0.1-SNAPSHOT.jar.originalAparecen dos ficheros, y la diferencia lo explica todo:
.jar.original(12 KB) es el JAR que produce Maven de forma estándar: solo tus clases compiladas..jar(22 MB) es el fat jar o uber jar: tus clases más todas las dependencias —Spring, Jackson, Tomcat— más un cargador especial.
El spring-boot-maven-plugin es quien realiza esa transformación en la fase package.
Qué es un JAR ejecutable y un fat jar
Un JAR normal es un ZIP con clases .class. Para ejecutarlo hacen falta todas sus dependencias en el classpath, lo que obliga a distribuir decenas de ficheros o a instalar un servidor de aplicaciones.
Spring Boot resuelve esto con un formato ingenioso:
ciclourbana-0.0.1-SNAPSHOT.jar
├── META-INF/
│ └── MANIFEST.MF ← declara Main-Class y Start-Class
├── org/springframework/boot/loader/ ← el cargador de Spring Boot
├── BOOT-INF/
│ ├── classes/ ← TUS clases compiladas
│ │ └── com/ciclourbana/...
│ └── lib/ ← TODAS las dependencias, como .jar anidados
│ ├── spring-web-6.x.jar
│ ├── tomcat-embed-core-10.x.jar
│ └── jackson-databind-2.x.jar
└── ...Puedes verificarlo:
unzip -l target/ciclourbana-0.0.1-SNAPSHOT.jar | head -20
unzip -p target/ciclourbana-0.0.1-SNAPSHOT.jar META-INF/MANIFEST.MFEl manifiesto muestra la clave del truco:
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.ciclourbana.CicloUrbanaApplicationCuando ejecutas el JAR, Java invoca el JarLauncher de Spring Boot, no tu clase. Ese lanzador instala un cargador de clases capaz de leer JAR anidados dentro de BOOT-INF/lib —algo que Java estándar no sabe hacer— y solo entonces llama a tu Start-Class.
La consecuencia práctica es enorme: un único fichero contiene la aplicación completa, con su servidor incluido. Eso es lo que se copia a un servidor, se mete en una imagen Docker o se sube a una plataforma cloud.
Ejecutar el JAR
Arranca exactamente igual que con spring-boot:run. Comprueba que sigue respondiendo:
Puedes pasar propiedades por la línea de comandos:
# Cambiar el puerto sin recompilar
java -jar target/ciclourbana-0.0.1-SNAPSHOT.jar --server.port=9090
# Limitar la memoria de la JVM (útil en contenedores)
java -Xmx256m -jar target/ciclourbana-0.0.1-SNAPSHOT.jarFíjate en la diferencia: -Xmx256m va antes de -jar porque es una opción de la JVM, mientras que --server.port=9090 va después porque es un argumento de la aplicación.
- Spring Boot DevTools y el reinicio automático
Al generar el proyecto añadimos spring-boot-devtools:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>Los atributos <optional>true</optional> y <scope>runtime</scope> hacen que DevTools no se propague a quien dependa de tu proyecto y que se desactive automáticamente cuando la aplicación se ejecuta desde un fat jar. Es decir: ayuda en desarrollo y desaparece en producción sin que hagas nada.
Qué aporta:
| Función | Efecto |
|---|---|
| Reinicio automático | Al detectar clases recompiladas, reinicia el contexto de Spring en menos de un segundo |
| LiveReload | Refresca el navegador automáticamente al cambiar recursos estáticos |
| Cachés desactivadas | Desactiva las cachés de plantillas para ver los cambios al instante |
| Propiedades de desarrollo | Aplica valores por defecto sensatos para desarrollo |
Cómo funciona el reinicio rápido
DevTools usa dos cargadores de clases: uno base con las dependencias (Spring, Tomcat, Jackson), que no cambian nunca, y uno restart con tus clases, que sí cambian. Al reiniciar solo desecha y recarga el segundo. Por eso tarda décimas de segundo en lugar de los dos segundos del arranque completo.
Ese es también el motivo de que el hilo principal aparezca en el log como restartedMain en lugar de main.
Provocar un reinicio
El reinicio se dispara cuando cambian los ficheros .class en target/classes, no cuando guardas el .java. Por tanto hace falta una recompilación:
- IntelliJ:
Ctrl+F9(Build Project), o activa Settings → Build → Compiler → Build project automatically. - Eclipse/STS: compila al guardar por defecto, así que basta con
Ctrl+S. - VS Code: también compila al guardar.
Pruébalo. Con la aplicación en marcha mediante ./mvnw spring-boot:run, añade una quinta estación:
Recompila y observa en el log:
2026-08-31T10:31:08.442+02:00 INFO --- [ restartedMain] c.c.CicloUrbanaApplication : Started CicloUrbanaApplication in 0.612 secondsAhora curl devuelve cinco estaciones sin que hayas parado nada.
Si el reinicio te molesta, puedes desactivarlo sin quitar la dependencia:
Errores Comunes y Consejos
Web server failed to start. Port 8080 was already in use.Tienes otra instancia arrancada, muy típico si olvidaste parar la del IDE antes de lanzar./mvnw spring-boot:run. Localiza el proceso conlsof -i :8080(Linux/macOS) onetstat -ano | findstr :8080(Windows), o arranca en otro puerto con--server.port=9090.- El endpoint devuelve 404 aunque el código parece correcto. Casi siempre es porque el controlador está fuera del paquete raíz
com.ciclourbana. El escaneo de componentes solo mira ese paquete y sus subpaquetes; lo veremos en la lección 01-04. - La aplicación arranca y termina inmediatamente. Falta
spring-boot-starter-web. Sin dependencia web no hay servidor que mantenga vivo el proceso, así que elmainacaba y la JVM se cierra. - DevTools no reinicia nada. Estás guardando el
.javapero no se recompila. Activa la construcción automática en el IDE o compila a mano. - Ejecutar el
.jar.originalpor error. Dano main manifest attribute. El fichero bueno es el.jargrande, sin sufijo. - Consejo — el JAR es autocontenido, no autónomo. Contiene todas las dependencias Java, pero sigue necesitando una JVM instalada donde se ejecute. Por eso las imágenes Docker de Spring Boot parten de una imagen con JDK o JRE (módulo 7).
- Consejo — inicializa Git ya. El proyecto trae un
.gitignorecorrecto. Congit init && git add . && git commit -m "Proyecto inicial de CicloUrbana"tendrás un punto de retorno seguro desde el primer día.
Ejercicios
Ejercicio 1
Genera el proyecto ciclourbana por línea de comandos con curl, ejecútalo y comprueba con curl que GET /api/v1/estaciones devuelve las cuatro estaciones de Ribalta. Anota el tiempo de arranque que aparece en el log.
Ejercicio 2
Añade al EstacionController un segundo endpoint GET /api/v1/estaciones/resumen que devuelva un objeto JSON con el número total de estaciones y la capacidad total sumada de la red. Usa un record ResumenRed.
Ejercicio 3
Empaqueta la aplicación, inspecciona el contenido del fat jar para localizar tus clases compiladas y el JAR de Tomcat embebido, y ejecútala en el puerto 9090 comprobando que responde.
Soluciones
Solución 1
curl https://start.spring.io/starter.zip \
-d type=maven-project -d language=java \
-d groupId=com.ciclourbana -d artifactId=ciclourbana \
-d name=ciclourbana -d packageName=com.ciclourbana \
-d packaging=jar -d javaVersion=21 \
-d dependencies=web,devtools \
-o ciclourbana.zip
unzip ciclourbana.zip -d ciclourbana
cd ciclourbana
chmod +x mvnwTras crear Estacion y EstacionController como se describe en la lección:
En otra terminal:
curl -s http://localhost:8080/api/v1/estaciones | jq 'length'
# 4
curl -s http://localhost:8080/api/v1/estaciones | jq '.[].nombre'
# "Plaza Mayor"
# "Estación Norte"
# "Parque del Río"
# "Universidad"El tiempo de arranque aparece en la línea Started CicloUrbanaApplication in X seconds. En una máquina normal está entre 1,5 y 3 segundos.
Solución 2
Primero el record del resumen, en el mismo paquete:
package com.ciclourbana.estaciones;
/**
* Resumen agregado de la red de estaciones de Ribalta.
*/
public record ResumenRed(
int totalEstaciones,
int capacidadTotal
) {
}Y el nuevo método en el controlador:
@GetMapping("/resumen")
public ResumenRed obtenerResumen() {
int capacidadTotal = ESTACIONES.stream()
.mapToInt(Estacion::capacidad) // referencia al accesor del record
.sum();
return new ResumenRed(ESTACIONES.size(), capacidadTotal);
}Explicación detallada:
@GetMapping("/resumen")se concatena con el@RequestMappingde la clase, produciendoGET /api/v1/estaciones/resumen.Estacion::capacidades una referencia a método. En un record, el accesor se llama igual que el componente (capacidad(), nogetCapacidad()).mapToInt(...).sum()convierte el flujo a unIntStreamy suma los valores, evitando el autoboxing.- Devolver un objeto (no una lista) hace que Jackson genere un objeto JSON, no un array.
Comprobación:
curl -s http://localhost:8080/api/v1/estaciones/resumen | jq
# {
# "totalEstaciones": 4,
# "capacidadTotal": 108
# }Solución 3
./mvnw clean package
# Localizar las clases propias dentro del fat jar
unzip -l target/ciclourbana-0.0.1-SNAPSHOT.jar | grep "com/ciclourbana"
# BOOT-INF/classes/com/ciclourbana/CicloUrbanaApplication.class
# BOOT-INF/classes/com/ciclourbana/estaciones/Estacion.class
# BOOT-INF/classes/com/ciclourbana/estaciones/EstacionController.class
# Localizar Tomcat embebido
unzip -l target/ciclourbana-0.0.1-SNAPSHOT.jar | grep tomcat
# BOOT-INF/lib/tomcat-embed-core-10.1.x.jar
# BOOT-INF/lib/tomcat-embed-el-10.1.x.jar
# BOOT-INF/lib/tomcat-embed-websocket-10.1.x.jar
# Ejecutar en el puerto 9090
java -jar target/ciclourbana-0.0.1-SNAPSHOT.jar --server.port=9090Verificación en otra terminal:
Conclusión del ejercicio: tus clases viven en BOOT-INF/classes y las dependencias en BOOT-INF/lib como JAR anidados. Esa separación es exactamente la que permite a Spring Boot construir imágenes Docker por capas eficientes, algo que aprovecharemos en el módulo 7.
Conclusión
Ya tienes CicloUrbana en marcha. Has generado el proyecto con Spring Initializr desde la web y desde la terminal, has entendido las diez líneas de la clase de arranque, has creado el record Estacion y el EstacionController que expone GET /api/v1/estaciones con las cuatro estaciones de Ribalta, y lo has ejecutado con Maven, con el IDE y como fat jar autocontenido con java -jar. También sabes por qué ese JAR pesa 22 MB y cómo el JarLauncher carga los JAR anidados de BOOT-INF/lib.
En la siguiente lección, Entendiendo la Estructura del Proyecto, abriremos la caja: recorreremos el árbol de directorios generado, leeremos el pom.xml línea a línea, entenderemos qué es exactamente un starter y por qué el paquete raíz determina qué componentes encuentra Spring, y diseñaremos la organización de paquetes que CicloUrbana mantendrá durante todo el curso.
Curso de Spring Boot
Módulo 1: Introducción a Spring Boot
- ¿Qué es Spring Boot?
- Configuración de tu Entorno de Desarrollo
- Creando tu Primera Aplicación Spring Boot
- Entendiendo la Estructura del Proyecto
- El Arranque y el Ciclo de Vida de la Aplicación
Módulo 2: Conceptos Básicos de Spring Boot
- Anotaciones de Spring Boot
- Inyección de Dependencias en Spring Boot
- Ámbito y Ciclo de Vida de los Beans
- Configuración de Spring Boot
- Propiedades de Spring Boot
- Autoconfiguración y Starters por Dentro
Módulo 3: Construyendo Servicios Web RESTful
- Introducción a los Servicios Web RESTful
- Creando Controladores REST
- Manejo de Métodos HTTP
- Validación de Datos de Entrada
- DTOs y Mapeo entre Capas
- Manejo de Excepciones en REST
- Documentar la API con OpenAPI
Módulo 4: Acceso a Datos con Spring Boot
- Introducción a Spring Data JPA
- Configuración de Fuentes de Datos
- Creación de Entidades JPA
- Relaciones entre Entidades
- Uso de Repositorios de Spring Data
- Métodos de Consulta en Spring Data JPA
- Transacciones y Gestión de la Persistencia
- Migraciones de Esquema con Flyway
Módulo 5: Seguridad en Spring Boot
- Introducción a Spring Security
- Configuración de Spring Security
- Autenticación y Autorización de Usuarios
- Implementación de Autenticación JWT
- Seguridad a Nivel de Método y Endurecimiento de la API
Módulo 6: Pruebas en Spring Boot
- Introducción a las Pruebas
- Pruebas Unitarias con JUnit
- Simulación con Mockito
- Pruebas de Integración
- Pruebas con Testcontainers
Módulo 7: Funciones Avanzadas de Spring Boot
- Spring Boot Actuator
- Perfiles de Spring Boot
- Tareas Programadas y Ejecución Asíncrona
- Spring Boot con Docker
- Spring Boot y Microservicios
- Comunicación entre Servicios y Tolerancia a Fallos
Módulo 8: Despliegue de Aplicaciones Spring Boot
- Introducción al Despliegue
- Desplegando en Heroku
- Desplegando en AWS
- Desplegando en Kubernetes
- Integración y Entrega Continua
Módulo 9: Rendimiento y Monitoreo
- Ajuste de Rendimiento
- Caché con Spring Cache
- Monitoreo con Spring Boot Actuator
- Uso de Prometheus y Grafana
- Gestión de Registros y Logs
- Trazabilidad Distribuida
