Introducción a Spring MVC: Configuración, Anotaciones y Manejo de Peticiones

Fundamentos del Framework Web Spring MVC

Spring MVC es un framework de aplicación web de la capa de presentación, basado en el patrón de diseño Modelo-Vista-Controlador (MVC). Se integra de forma nativa con el contenedor de IoC y el soporte para AOP del núcleo de Spring. Permite que clases POJO simples actúen como controladores mediante anotaciones, sin necesidad de implementar interfaces específicas.

Configuarción Básica y Flujo de Trabajo

El desarrollo con Spring MVC sigue un flujo de petición-respuesta y separa claramente las responsabilidades de la capa web. El componente central es el DispatcherServlet, que actúa como controlador frontal.

1. Configuración del Descriptor de Despliegue (web.xml)

Se debe declarar y configurar el DispatcherServlet. Es recomendable especificar la ubicación del archivo de configuración de Spring MVC mediante el parámetro de inicialización contextConfigLocation.

<servlet>
    <servlet-name>mvcDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:config/application-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>mvcDispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

2. Configuración del Contexto de Spring MVC

El archivo de configuración define la exploración de componentes y el resolutor de vistas.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="... schema locations ...">

    <context:component-scan base-package="com.example.web.controllers"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

3. Implementación de un Controlador Simple

Un controlador se marca con la anotación @Controller. El método que maneja la petición se anota con @RequestMapping.

package com.example.web.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class WelcomeHandler {

    @RequestMapping("/greet")
    public String showGreetingPage() {
        System.out.println("Manejador de saludo invocado.");
        return "welcome"; // Resuelto a /WEB-INF/pages/welcome.jsp
    }
}

La Anotación @RequestMapping y sus Atributos

La anotación @RequestMapping es fundamental para mapear peticiones HTTP a métodos de controlador. Puede aplicarse a nivel de clase y de método. Sus atributos permiten un mapeo preciso.

Mapeo por Método HTTP (method)

Restringe el tipo de verbo HTTP que puede invocar el método.

@Controller
@RequestMapping("/api/users")
public class UserApiController {

    @RequestMapping(value = "/create", method = RequestMethod.POST)
    public String createUser(User newUser) {
        // Lógica para crear usuario
        return "result";
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String getUserProfile(@PathVariable Long id) {
        // Lógica para obtener usuario
        return "profile";
    }
}

Mapeo por Parámetros (params) y Cabeceras (headers)

Permite condiciones adicionales basadas en parámetros de consulta o cabeceras HTTP.

// Solo se ejecuta si la petición incluye ?source=internal
@RequestMapping(value = "/data", params = "source=internal")
public String fetchInternalData() { return "dataView"; }

// Solo se ejecuta si la cabecera 'X-Custom-Header' está presente
@RequestMapping(value = "/secure", headers = "X-Custom-Header")
public String secureEndpoint() { return "secureView"; }

Patrones Ant y Variables de Ruta (@PathVariable)

Soporta patrones de URL estilo Ant y la captura de segmentos de la ruta.

// Patrón Ant: /files/2024/*.pdf
@RequestMapping("/files/{year}/{filename:.+}")
public String serveFile(@PathVariable String year, @PathVariable String filename) {
    System.out.println("Año: " + year + ", Archivo: " + filename);
    return "download";
}

// Captura múltiples segmentos con **
@RequestMapping("/docs/**/summary")
public String showDocSummary() {
    return "docSummary";
}

Estilo Arquitectónico REST y Filtro HiddenHttpMethodFilter

Spring MVC facilita la creación de APIs RESTful, donde los recursos se identifican por URL y las operacioens por verbos HTTP (GET, POST, PUT, DELETE).

Configuración del Filtro para Verbos HTTP

Dado que los formularios HTML solo soportan GET y POST, se utiliza un filtro para simular PUT y DELETE mediante un parámetro oculto.

<!-- En web.xml -->
<filter>
    <filter-name>httpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>httpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Ejemplo de Controlador RESTful

@RestController // Combina @Controller y @ResponseBody
@RequestMapping("/api/orders")
public class OrderRestController {

    @GetMapping("/{orderId}")
    public Order getOrder(@PathVariable String orderId) {
        return orderService.findById(orderId);
    }

    @PostMapping
    public ResponseEntity<Void> placeOrder(@RequestBody Order newOrder) {
        orderService.save(newOrder);
        return ResponseEntity.created(URI.create("/api/orders/" + newOrder.getId())).build();
    }

    @PutMapping("/{orderId}")
    public ResponseEntity<Void> updateOrder(@PathVariable String orderId, @RequestBody Order orderData) {
        orderService.update(orderId, orderData);
        return ResponseEntity.ok().build();
    }

    @DeleteMapping("/{orderId}")
    public ResponseEntity<Void> cancelOrder(@PathVariable String orderId) {
        orderService.delete(orderId);
        return ResponseEntity.noContent().build();
    }
}

Obtención de Datos de la Petición en el Controlador

Spring MVC ofrece varias formas de acceder a los datos de la petición HTTP dentro de los métodos del controlador.

Uso de @RequestParam y @RequestHeader

@RequestMapping("/submit")
public String handleSubmission(@RequestParam(value = "user", defaultValue = "guest") String username,
                               @RequestParam("token") String accessToken,
                               @RequestHeader("User-Agent") String userAgent) {
    System.out.println("Usuario: " + username + ", Agente: " + userAgent);
    return "confirmation";
}

Enlace Automático a Objetos POJO

Los parámetros de la petición se pueden vincular automáticamente a las propiedades de un objeto Java.

public class RegistrationForm {
    private String fullName;
    private String email;
    private Integer age;
    // Getters y Setters
}

@PostMapping("/register")
public String processRegistration(RegistrationForm form) {
    System.out.println("Registrando: " + form.getFullName());
    return "registered";
}

Acceso a APIs Nativas de Servlet

Los métodos del controlador pueden declarar parámetros de tipos como HttpServletRequest, HttpServletResponse o HttpSession para acceso directo.

@RequestMapping("/info")
public String getClientInfo(HttpServletRequest req, HttpServletResponse resp) {
    String remoteAddr = req.getRemoteAddr();
    // ... lógica con la respuesta si es necesario
    return "infoPage";
}

Preparación de Datos para la Vista (Modelo)

Existen varias estrategias para pasar datos del controlador a la vista.

Devolviendo un Objeto ModelAndView

@RequestMapping("/dashboard")
public ModelAndView showDashboard() {
    ModelAndView mav = new ModelAndView("dashboardView"); // Nombre de la vista
    mav.addObject("currentUser", userService.getCurrentUser());
    mav.addObject("recentActivities", activityService.getRecent(10));
    return mav;
}

Usando un Parámetro Map o Model

Spring inyecta automáticamente un modelo mutable en estos parámetros.

@RequestMapping("/products")
public String listProducts(Model uiModel) {
    List<Product> productList = catalogService.getAllProducts();
    uiModel.addAttribute("products", productList);
    uiModel.addAttribute("pageTitle", "Catálogo de Productos");
    return "productList";
}

// Alternativa con Map<String, Object>
@RequestMapping("/report")
public String generateReport(Map<String, Object> modelAttributes) {
    modelAttributes.put("reportData", reportGenerator.run());
    return "reportView";
}

Etiquetas: SpringMVC JavaEE DesarrolloWeb FrameworkMVC RESTfulAPI

Publicado el 10-8 05:22