Guía de Introducción a Spring Boot: Cocinando Aplicaciones con un Chef Java

Aprende a desarrollar aplicaciones Java de forma ágil y eficiente con Spring Boot, el framework que automatiza configuraciones y acelera tu desarrollo.


Introducción: Nuestro Chef de Cocina Java

Preparación automática

Prepara automáticamente los ingredientes (dependencias).

Configuración perfecta

Ajusta el horno a la temperatura justa (configuración automática).

Desarrollo ágil

Sirve platos rápidamente (desarrollo ágil).

Recetas reutilizables

Y nos da recetas reutilizables (anotaciones y convenciones).

Imaginemos que Spring Boot es como un chef experto que nos guía para preparar platos sofisticados (aplicaciones Java), sin que tengamos que preocuparnos por todos los ingredientes técnicos o técnicas complicadas.

¿Cómo iniciamos un nuevo proyecto?

Tres formas de preparar nuestro entorno de cocina Spring Boot:

Spring Initializr (la cocina asistida)

Acceder a https://start.spring.io y seleccionar:

  • Grupo: com.ejemplo
  • Artefacto: demo
  • Dependencias: Spring Web, Spring Boot DevTools, Lombok

Descargar el proyecto .zip, descomprimir e importar en el IDE.

Línea de comandos

curl https://start.spring.io/starter.zip -d dependencies=web,devtools,lombok -d name=demo -d type=maven-project -d language=java -o demo.zip


Desde el IDE

IDE como IntelliJ IDEA o Spring Tool Suite permiten crear proyectos Spring Boot con asistentes.

Las anotaciones más importantes: Ingredientes secretos

Primer plato: Hola Mundo Web (con vista HTML)

Controlador

@Controller public class HolaMundoController { @GetMapping("/") public String saludar(Model model) { model.addAttribute("mensaje", "¡Hola mundo desde Spring Boot!"); return "hola"; } }

Plantilla HTML

<!DOCTYPE html> <html> <head> <title>Hola</title> </head> <body> <h1 th:text="${mensaje}">Mensaje de prueba</h1> </body> </html>

Plantilla hola.html en src/main/resources/templates/

Dependencia necesaria en pom.xml:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>

Segundo plato: Hola Mundo REST (API simple)

Escribir el controlador

Crear una clase con la anotación @RestController

Definir el endpoint

Usar @GetMapping para especificar la ruta

Retornar respuesta

Spring convertirá automáticamente a JSON

@RestController public class HolaMundoRestController { @GetMapping("/api/hola") public String saludar() { return "¡Hola mundo desde una API REST!"; } }

Las anotaciones más importantes: Ingredientes secretos

¿Qué es @Autowired y para qué sirve?

La anotación @Autowired es uno de los ingredientes principales en la cocina de Spring. Permite inyectar automáticamente dependencias en nuestros componentes, es decir, pedirle al chef que nos traiga los objetos que necesitamos sin tener que crearlos manualmente.

¿Dónde y cuándo usarla?

Se puede aplicar en:

  • Atributos de clase
  • Constructores (preferido)
  • Métodos setter

Se debe usar cuando una clase necesita otra clase para funcionar. En lugar de instanciarla con new, dejamos que Spring se encargue de proporcionarla desde el contenedor.

Ejemplo detallado

Supongamos que tenemos un servicio que prepara platos:

@Service public class CocinaService { public String preparar(String nombre) { return "Plato preparado para " + nombre; } }

Y un controlador que necesita ese servicio:

@RestController public class RestauranteController { private final CocinaService cocinaService; @Autowired // Spring inyecta automáticamente la instancia de CocinaService public RestauranteController(CocinaService cocinaService) { this.cocinaService = cocinaService; } @GetMapping("/api/ordenar/{nombre}") public String ordenar(@PathVariable String nombre) { return cocinaService.preparar(nombre); } }

Spring detecta que RestauranteController necesita una instancia de CocinaService, la busca entre los componentes disponibles (@Service, @Component, @Repository) y la inyecta automáticamente.

Este patrón se conoce como Inyección de Dependencias, y permite un código más limpio, mantenible y fácil de probar.

Autowired con un sólo constructor

En versiones modernas de Spring (a partir de Spring 4.3), la anotación @Autowired ya no es necesaria en constructores si la clase tiene un único constructor. Spring la detecta automáticamente.


@Autowired public HomeController(MensajeService mensajeService) { this.mensajeService = mensajeService; } // Unnecessary `@Autowired` annotationvscode-spring-boot(JAVA_AUTOWIRED_CONSTRUCTOR) org.springframework.beans.factory.annotation.Autowired

Ingredientes Personalizados: Controladores con Parámetros

Parámetros en la URL

@RequestParam permite capturar parámetros de consulta

@RestController public class ChefRestController { @GetMapping("/api/saludo") public String saludar(@RequestParam String nombre) { return "Hola, " + nombre + "! Bienvenido a la cocina de Spring Boot."; } }

Parámetros en la ruta (path variables)

@PathVariable captura segmentos de la URL

@RestController public class PlatoDelDiaController { @GetMapping("/api/plato/{nombre}") public String platoDelDia(@PathVariable String nombre) { return "El plato del día para " + nombre + " es: Pasta al pesto."; } }

Dividiendo tareas en la cocina: Servicios

Controlador

Recibe peticiones y devuelve respuestas

Servicio

Contiene la lógica de negocio

Repositorio

Accede a los datos

Crear un Servicio:

@Service public class CocinaService { public String prepararPlato(String nombre) { return "Plato preparado especialmente para " + nombre; } }

Inyectar el Servicio en el Controlador:

@RestController public class CocinaController { private final CocinaService cocinaService; @Autowired public CocinaController(CocinaService cocinaService) { this.cocinaService = cocinaService; } @GetMapping("/api/preparar/{nombre}") public String preparar(@PathVariable String nombre) { return cocinaService.prepararPlato(nombre); } }

Menú completo: CRUD básico con receta de cursos

Empezando con el Modelo

Clase Curso (Modelo)

@Entity public class Curso { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String nombre; private String descripcion; // Getters y setters }

Creando el acceso a datos

Repositorio

@Repository public interface CursoRepository extends JpaRepository { }

Implementando la lógica de negocio

Servicio

@Service public class CursoService { @Autowired private CursoRepository repo; public List listar() { return repo.findAll(); } public Curso guardar(Curso curso) { return repo.save(curso); } public Optional buscar(Long id) { return repo.findById(id); } public void eliminar(Long id) { repo.deleteById(id); } }

Controlador REST para CRUD de Cursos

Listar todos los cursos

Método GET que devuelve una lista completa

Guardar un nuevo curso

Método POST que recibe un objeto JSON

Buscar un curso por ID

Método GET con parámetro de ruta

Eliminar un curso

Método DELETE con parámetro de ruta

@RestController @RequestMapping("/api/cursos") public class CursoController { @Autowired private CursoService servicio; @GetMapping public List listar() { return servicio.listar(); } @PostMapping public Curso guardar(@RequestBody Curso curso) { return servicio.guardar(curso); } @GetMapping("/{id}") public ResponseEntity obtener(@PathVariable Long id) { return servicio.buscar(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @DeleteMapping("/{id}") public ResponseEntity eliminar(@PathVariable Long id) { servicio.eliminar(id); return ResponseEntity.noContent().build(); } }

Ingrediente extra: Base de datos en memoria H2

¿Qué es H2?

H2 es una base de datos relacional escrita en Java. Es muy rápida, de código abierto, y puede funcionar en modo embebido (en memoria) o en modo servidor.

¿Por qué usar H2 con Spring Boot?

Es perfecta para desarrollo y pruebas porque se inicia rápidamente, no requiere instalación separada, y los datos se resetean al reiniciar la aplicación.

Configuración en application.properties
spring.h2.console.enabled=true spring.datasource.url=jdbc:h2:mem:cursosdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=update

Acceder a http://localhost:8080/h2-console para consultar la base de datos.

Validaciones con Bean Validation

Agregar dependencia:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>

Usar anotaciones en la entidad:

public class Curso { @NotBlank private String nombre; @Size(min = 10, max = 200) private String descripcion; // ... }

Validar en el controlador:

@PostMapping public Curso guardar(@Valid @RequestBody Curso curso) { return servicio.guardar(curso); }

Uso de DTOs (Data Transfer Objects)

Evitar exponer entidades directamente. Crear clases DTO:

public class CursoDTO { private String nombre; private String descripcion; }

Convertir desde/hacia entidad:

public CursoDTO toDto(Curso curso) { CursoDTO dto = new CursoDTO(); dto.setNombre(curso.getNombre()); dto.setDescripcion(curso.getDescripcion()); return dto; }

Pruebas unitarias con Spring Boot

Agregar dependencia en pom.xml

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

Ubicación del código de prueba

Los tests deben colocarse en el directorio src/test/java, siguiendo el mismo paquete que la clase que se desea probar. Por ejemplo, si la clase CursoService está en:

src/main/java/com/ejemplo/servicio/CursoService.java

El test deberá estar en:

src/test/java/com/ejemplo/servicio/CursoServiceTest.java

Ejemplo con JUnit:

@SpringBootTest public class CursoServiceTest { @Autowired private CursoService servicio; @Test public void testGuardarCurso() { Curso curso = new Curso(); curso.setNombre("Java Básico"); Curso resultado = servicio.guardar(curso); assertNotNull(resultado.getId()); } }


Cómo ejecutar las pruebas

Desde el IDE (por ejemplo IntelliJ IDEA o Eclipse):

  • Hacer clic derecho sobre el archivo CursoServiceTest.java y seleccionar Run o Run with Coverage.

Desde la línea de comandos con Maven:

./mvnw test

Esto ejecutará todos los tests definidos en src/test/java y mostrará el resultado en consola.

Agregar dependencia:

Relaciones entre entidades

Ejemplo: un curso tiene una lista de alumnos.

@Entity public class Alumno { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String nombre; @ManyToOne private Curso curso; } @Entity public class Curso { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String nombre; @OneToMany(mappedBy = "curso") private List<Alumno> alumnos; }

¿Qué es @Service y para qué sirve?

La anotación @Service indica que una clase se comporta como un servicio dentro de la lógica de negocio de la aplicación. Spring la detecta automáticamente y la registra como un componente gestionado por el contenedor.

  • Se usa para separar la lógica del negocio del resto de la aplicación.
  • Facilita la reutilización y prueba de esa lógica.

Ejemplo:

@Service public class CalculadoraService { public int sumar(int a, int b) { return a + b; } }

¿Qué es @Repository y para qué sirve?

La anotación @Repository marca una clase como un componente de acceso a datos. Además de registrarla como componente, Spring proporciona capacidades adicionales como el manejo automático de excepciones relacionadas con la persistencia.

  • Se aplica a interfaces que extienden JpaRepository, CrudRepository, etc.
  • Se usa también en clases personalizadas de acceso a datos.
@Repository public interface ProductoRepository extends JpaRepository<Producto, Long> { }


¿Qué es @Component y para qué sirve?

@Component es la anotación genérica para marcar una clase como componente gestionado por Spring. A diferencia de @Service o @Repository, no tiene semántica de dominio asociada.

  • Se puede usar para cualquier clase que deba ser detectada e inyectada por Spring.
@Component public class GestorMensajes { public void enviar(String texto) { System.out.println("Mensaje enviado: " + texto); } }

Flujo completo de una aplicación Spring Boot

Petición HTTP

El cliente envía una solicitud al servidor

Controlador

Recibe la petición y la dirige al servicio adecuado

Servicio

Ejecuta la lógica de negocio y utiliza el repositorio

Repositorio

Interactúa con la base de datos y devuelve resultados

Spring Boot facilita este flujo mediante la inyección de dependencias y la configuración automática, permitiendo que los desarrolladores se centren en la lógica de negocio en lugar de en la infraestructura.

Beneficios de usar Spring Boot

70%

Reducción de código

Menos código boilerplate comparado con Spring tradicional

85%

Configuración automática

Porcentaje de configuraciones que Spring Boot maneja automáticamente

50%

Tiempo de desarrollo

Reducción aproximada en el tiempo de desarrollo de aplicaciones

Spring Boot actúa como un chef experto que nos permite crear aplicaciones Java sofisticadas sin preocuparnos por todos los detalles técnicos, permitiéndonos concentrarnos en lo que realmente importa: la lógica de negocio de nuestra aplicación.

Recetas avanzadas con Spring Boot

Spring Security

Añade autenticación y autorización a tu aplicación con configuraciones sencillas.

Spring Cloud

Desarrolla aplicaciones distribuidas y microservicios con facilidad.

Spring Data

Simplifica el acceso a datos con repositorios predefinidos para diferentes bases de datos.

Spring Test

Herramientas para probar cada capa de tu aplicación de forma aislada o integrada.

Una vez que domines los conceptos básicos de Spring Boot, puedes explorar estos módulos adicionales que te permitirán crear aplicaciones más robustas y completas, como un chef que domina técnicas culinarias avanzadas.