
Conceptos que el curso da por sabidos
El material avanzado entra rápido. La primera lección del módulo siguiente trabaja Lombok asumiendo que el alumno entiende qué hace @Entity y @Service sin pensarlo, la primera lección de JPA avanzado trabaja Entity Graphs asumiendo que las asociaciones @OneToMany y @ManyToOne son territorio conocido, y los módulos posteriores asumen que el alumno ya sabe escribir un controller, exponer una API REST y probarla con MockMvc.
Esta lección es un chequeo diagnóstico organizado en seis bloques. No es un re-aprendizaje: cada bloque revisa la idea esencial, muestra un fragmento de código de referencia y termina con una pregunta de autoevaluación. Si el alumno responde con seguridad a las seis, está listo para el resto del curso.
Si tras el repaso queda alguna pregunta sin respuesta clara, lo recomendable es revisar el módulo correspondiente del curso de Spring Boot fundamentos antes de continuar. El esfuerzo invertido en cerrar la base se devuelve con creces durante las lecciones avanzadas.
REST controllers y respuestas HTTP
El API REST se construye con @RestController (combinación de @Controller y @ResponseBody) y métodos anotados con @GetMapping, @PostMapping, @PutMapping, @PatchMapping y @DeleteMapping. La respuesta puede ser un objeto serializado a JSON automáticamente o un ResponseEntity con control fino sobre status code y headers.
@RestController
@RequestMapping("/api/empleados")
class EmpleadoController {
private final EmpleadoService service;
EmpleadoController(EmpleadoService service) {
this.service = service;
}
@GetMapping
List<EmpleadoDto> listar() {
return service.listar();
}
@PostMapping
ResponseEntity<EmpleadoDto> crear(@Valid @RequestBody EmpleadoCrearDto dto) {
var creado = service.crear(dto);
var location = URI.create("/api/empleados/" + creado.id());
return ResponseEntity.created(location).body(creado);
}
}
Los DTOs se modelan habitualmente con records de Java (record EmpleadoDto(Long id, String nombre, BigDecimal salario)) y la validación entra con @Valid sobre el cuerpo y anotaciones de jakarta.validation.constraints (@NotNull, @Email, @Min) en los campos.
Autoevaluación: ¿Sabes diferenciar cuándo conviene devolver un objeto directamente y cuándo
ResponseEntity, y por qué@ResponseStatuspuede ser una alternativa más concisa para responses sin headers personalizados?
Persistencia con Spring Data JPA
Las entidades se mapean con @Entity, asociaciones con @OneToMany/@ManyToOne/@ManyToMany, y los repositorios extienden JpaRepository<T, ID> para obtener CRUD y queries derivadas a partir del nombre del método.
@Entity
class Empleado {
@Id @GeneratedValue
private Long id;
private String nombre;
private BigDecimal salario;
@ManyToOne(fetch = FetchType.LAZY)
private Departamento departamento;
// getters/setters/equals omitidos
}
interface EmpleadoRepository extends JpaRepository<Empleado, Long> {
List<Empleado> findByDepartamentoNombre(String nombre);
List<Empleado> findBySalarioGreaterThanEqual(BigDecimal min);
@Query("SELECT e FROM Empleado e WHERE e.salario > :min")
List<Empleado> conSalarioMayorQue(BigDecimal min);
}
El curso avanzado parte de aquí y lleva la idea más lejos con Entity Graphs para evitar el problema N+1, Criteria Builder para queries dinámicas y locking explícito.
Autoevaluación: ¿Tienes claro qué hace
fetch = FetchType.LAZYpor defecto en@ManyToOney por quéfindAllpuede dispararse en cien queries cuando recorres la lista?
Validación con Bean Validation
Las validaciones declarativas con anotaciones de jakarta.validation.constraints aplicadas a DTOs y entidades, junto a @Valid en el controller, lanzan MethodArgumentNotValidException que el framework traduce automáticamente a respuestas 400.
record EmpleadoCrearDto(
@NotBlank @Size(max = 100) String nombre,
@NotNull @Min(value = 0) BigDecimal salario,
@Email String email
) {}
El curso avanzado retoma esto en la lección de manejo de errores avanzado con ProblemDetails RFC 7807 y catálogo i18n.
Autoevaluación: ¿Sabes cómo capturar
MethodArgumentNotValidExceptionen un@RestControllerAdvicepara devolver una respuesta JSON estructurada con la lista de campos inválidos?
Spring Security a nivel intermedio
La autenticación con JWT sobre APIs REST requiere configurar un SecurityFilterChain, definir un JwtAuthenticationFilter que valide el token, exponer endpoints públicos (/login, /register) y proteger los demás. El curso de Spring Security del catálogo cubre esto en detalle.
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http, JwtAuthenticationFilter jwtFilter) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/api/public/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
Autoevaluación: ¿Distingues
authenticated()depermitAll()y sabes en qué orden se ejecuta el filtro JWT respecto aUsernamePasswordAuthenticationFilter?
Testing unitario y de integración
El testing intermedio cubre JUnit 6 con @Test, @BeforeEach, @DisplayName, Mockito 5 con @Mock, @InjectMocks, when().thenReturn() y verify(), y los tests de Spring Boot con @SpringBootTest (carga completa) y MockMvc para tests de controladores.
@SpringBootTest
@AutoConfigureMockMvc
class EmpleadoControllerTest {
@Autowired MockMvc mockMvc;
@MockitoBean EmpleadoService service;
@Test
@DisplayName("GET /api/empleados devuelve 200 y la lista")
void listar_ok() throws Exception {
when(service.listar()).thenReturn(List.of(new EmpleadoDto(1L, "Ana", BigDecimal.valueOf(50000))));
mockMvc.perform(get("/api/empleados"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].nombre").value("Ana"));
}
}
El curso avanzado profundiza con slice tests (@WebMvcTest, @DataJpaTest, @JsonTest) que cargan solo la capa necesaria y son mucho más rápidos.
Autoevaluación: ¿Sabes cuándo conviene
@SpringBootTest(carga completa) y cuándo bastaría con un test de unidad sin contexto Spring?
Arquitectura de microservicios con Spring Cloud
A nivel intermedio se asume el conocimiento de Spring Cloud Config para configuración centralizada, Eureka o Consul para service discovery, Spring Cloud Gateway como punto de entrada único, OpenFeign como cliente HTTP declarativo y Resilience4J para circuit breakers y retries.
@FeignClient(name = "empleado-service")
interface EmpleadoClient {
@GetMapping("/api/empleados/{id}")
EmpleadoDto buscarPorId(@PathVariable Long id);
}
El curso avanzado no repite este contenido (ya está en el curso dedicado de Microservicios con Spring Cloud), pero sí aborda alternativas modernas: @HttpExchange como sustituto nativo de OpenFeign en Spring 6+ que no requiere Spring Cloud.
Autoevaluación: ¿Tienes claro qué problema resuelve un circuit breaker y cuándo conviene
RETRYen lugar de fallar rápido?
Si todo encaja, sigamos
Si las seis preguntas de autoevaluación tienen respuesta clara, el alumno está preparado para el resto del curso. La siguiente lección presenta el itinerario módulo a módulo y propone cómo aprovechar mejor el contenido según el rol profesional del alumno.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Spring Boot es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Spring Boot
Explora más contenido relacionado con Spring Boot y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Repasar los conceptos de Spring Boot intermedio que el curso asume. Detectar lagunas antes de entrar en el material avanzado. Reconocer la sintaxis básica de REST, JPA, Security, testing y arquitectura de microservicios.