Skip to content

Latest commit

 

History

History

34-Spring-MVC

// concepto

Spring MVC implementa el patrón Front Controller: toda request HTTP entra por un único punto — el DispatcherServlet — que la enruta al handler correcto.

Ciclo de vida de una request en Spring MVC:

HTTP Request
    ↓
DispatcherServlet          ← punto de entrada único (Front Controller)
    ↓
HandlerMapping             ← ¿qué @Controller/@RestController maneja esta URL?
    ↓
HandlerAdapter             ← invoca el método anotado
    ↓
@Controller method         ← lógica de negocio, devuelve datos o ModelAndView
    ↓
MessageConverter / View    ← serializa a JSON (Jackson) o resuelve la vista
    ↓
HTTP Response

Con @RestController, los métodos devuelven el objeto directamente — Spring aplica HttpMessageConverter (Jackson por defecto) para serializar a JSON sin pasar por un motor de plantillas.

// key features

@Controller vs @RestController:

Anotación Devuelve Uso típico
@Controller Vista (nombre de template) Aplicaciones web con Thymeleaf/JSP
@RestController Datos serializados (JSON/XML) APIs REST — equivale a @Controller + @ResponseBody

Mapeo de rutas:

@RestController
@RequestMapping("/api/productos")   // prefijo común
public class ProductoController {

    @GetMapping("/{id}")            // GET /api/productos/42
    public Producto obtener(@PathVariable Long id) { ... }

    @GetMapping                     // GET /api/productos?categoria=libros
    public List<Producto> listar(@RequestParam String categoria) { ... }

    @PostMapping                    // POST /api/productos
    public ResponseEntity<Producto> crear(@Valid @RequestBody ProductoDto dto) { ... }

    @PutMapping("/{id}")            // PUT /api/productos/42
    public Producto actualizar(@PathVariable Long id, @RequestBody ProductoDto dto) { ... }

    @DeleteMapping("/{id}")         // DELETE /api/productos/42
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void eliminar(@PathVariable Long id) { ... }
}

ResponseEntity<T> — control total sobre la respuesta HTTP:

// Devuelve 201 Created con cabecera Location y el cuerpo
return ResponseEntity
    .created(URI.create("/api/productos/" + producto.getId()))
    .body(producto);

// Devuelve 404 con cuerpo vacío
return ResponseEntity.notFound().build();

Manejo centralizado de errores con @ControllerAdvice:

@RestControllerAdvice               // aplica a todos los controllers
public class GlobalExceptionHandler {

    @ExceptionHandler(RecursoNoEncontradoException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse manejarNotFound(RecursoNoEncontradoException ex) {
        return new ErrorResponse(404, ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse manejarValidacion(MethodArgumentNotValidException ex) {
        String errores = ex.getBindingResult().getFieldErrors()
            .stream().map(e -> e.getField() + ": " + e.getDefaultMessage())
            .collect(Collectors.joining(", "));
        return new ErrorResponse(400, errores);
    }
}

Validación del body con Bean Validation:

public class ProductoDto {
    @NotNull(message = "El nombre es obligatorio")
    @Size(min = 2, max = 100)
    private String nombre;

    @Positive
    private BigDecimal precio;
}

// En el controller:
@PostMapping
public ResponseEntity<Producto> crear(@Valid @RequestBody ProductoDto dto) { ... }
//                                     ^^^^^^ activa validación — lanza MethodArgumentNotValidException si falla

CORS con @CrossOrigin:

@CrossOrigin(origins = "https://mi-frontend.com")  // en el controller o método
@RestController
public class ProductoController { ... }

// O configuración global en WebMvcConfigurer:
// registry.addMapping("/api/**").allowedOrigins("https://mi-frontend.com");
// ventajas
  • Separación de capas limpia: Controller solo coordina — delega lógica al Service y persistencia al Repository.
  • Serialización automática JSON: Jackson convierte POJOs a JSON y viceversa sin código manual.
  • Manejo centralizado de errores: @ControllerAdvice evita try/catch en cada controller — un único lugar para todas las excepciones.
  • Validación declarativa: @Valid + Bean Validation annotations en el DTO, sin lógica de validación en el controller.
  • ResponseEntity<T> da control preciso sobre códigos HTTP, cabeceras y cuerpo sin comprometer la legibilidad.

Ver ExpRestController.java, ExpRequestMapping.java, ExpValidationMVC.java, ExpExceptionHandler.java, ExpInterceptor.java y ExpContentNegotiation.java para ejemplos ejecutables con @RestController, mapeo de rutas, validación, manejo de errores e interceptores.