Introducción a Spring MVC

Spring Web MVC es un marco web ligero basado en Java que implementa el patrón de diseño MVC (Modelo-Vista-Controlador), orientado a solicitudes.

Flujo de procesamiento de solicitudes en Spring MVC

  1. El usuario envía una solicitud al DispatcherServlet.
  2. El DispatcherServlet consulta al HandlerMapping para determinar el controlador adecuado.
  3. El DispatcherServlet utiliza el HandlerAdapter para invocar el método del controlador.
  4. El HandlerAdapter ejecuta el método de procesamiento del controlador.
  5. El nombre lógico de la vista se pasa al ViewResolver.
  6. La vista se renderiza.
  7. El control se devuelve al DispatcherServlet, que envía la respuesta al usuario.

Pasos esenciales para el desarrollo con Spring MVC

  1. Configurar el DispatcherServlet en web.xml para interceptar solicitudes.
  2. Definir el HandlerMapping para asignar solicitudes a controladores.
  3. Configruar el HandlerAdapter para soportar varios tipos de controladores.
  4. Implementra los controladores para manejar la lógica de negocio.
  5. Establecer el ViewResolver para reoslver nombres de vista a tecnologías de vista específicas.

Componentes principales de Spring MVC

  • Controlador frontal: DispatcherServlet
  • Mapeador de solicitudes: HandlerMapping
  • Adaptador de controladores: HandlerAdapter
  • Resolvedor de vistas: ViewResolver
  • Controladores o controladores de página: Controller
  • Validador: Validator
  • Objeto de comando: Vincula parámetros de solicitud a un objeto.
  • Objeto de formulario: Proporciona datos para visualización y envío en formularios.

Anotaciones frecuentes

  • @Controller: Marca una clase como controlador.
  • @RequestMapping: Define reglas de mapeo de solicitudes a métodos del controlador; puede aplicarse a clases y métodos con parámetros como value y method.
  • @RequestParam: Vincula parámetros de solicitud a argumentos del método; soporta value, required (si es falso, el tipo debe ser de referencia), y defaultValue.
  • @ModelAttribute: Vincula parámetros de solicitud a objetos de comando; puede usarse en parámetros de métodos para agregar datos al modelo, o en métodos no manejadores para inicialización de datos.
  • @SessionAttributes: Especifica atributos del ModelMap que deben almacenarse en la sesión; se aplica a nivel de clase.
  • @RequestBody: Utilizado para enlace de datos en desarrollos AJAX con formato JSON; requiere que el Content-Type del cliente sea application/json, de lo contrario puede generar error 415.

Configuración de Spring MVC en un proyecto

Archivo POM.xml

Se agregan dependencias para Spring MVC, JSTL y la API JSP de Tomcat.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.taglibs</groupId>
    <artifactId>taglibs-standard-impl</artifactId>
    <version>1.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jsp-api</artifactId>
    <version>9.0.50</version>
</dependency>

Archivo springmvc-servlet.xml en WEB-INF

Define la configuración del contexto de Spring MVC.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <context:component-scan base-package="com.ejemplo"/>
    <mvc:annotation-driven/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/vistas/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <mvc:resources location="/recursos-estaticos/img" mapping="/recursos-estaticos/img/**"/>
</beans>

Archivo web.xml

Configura el servlet de Spring MVC y filtros necesarios.

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <display-name>Aplicación Web de Ejemplo</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter>
        <filter-name>filtroCodificacion</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>filtroCodificacion</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Ejemplo básico: Manejo de diferentes tipos de respuesta

Controlador que demuestra redirecciones y reenvíos.

package com.ejemplo.controlador;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class EjemploControlador {
    @RequestMapping("/inicio")
    public String redirigirAPagina(HttpServletRequest solicitud) {
        solicitud.setAttribute("mensaje", "Reenvío a página");
        return "inicio";
    }
    @RequestMapping("/redirigirAccion")
    public String redirigirAccion(HttpServletRequest solicitud) {
        solicitud.setAttribute("mensaje", "Redirección a acción");
        return "redirect:inicio";
    }
    @RequestMapping("/redirigirPaginaEstatica")
    public String redirigirPaginaEstatica() {
        return "redirect:/paginaEstatica.jsp";
    }
    @RequestMapping("/reenvioAccion")
    public String reenvioAccion(HttpServletRequest solicitud) {
        solicitud.setAttribute("mensaje", "Reenvío a acción");
        return "forward:redirigirPaginaEstatica";
    }
    @RequestMapping("/reenvioVistaProtegida")
    public String reenvioVistaProtegida(HttpServletRequest solicitud) {
        solicitud.setAttribute("mensaje", "Reenvío a vista en WEB-INF");
        return "vistaProtegida";
    }
}

Vista JSP correspondiente.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Ejemplo Spring MVC</title>
</head>
<body>
    <p>Hola, este es un ejemplo básico.</p>
    <p>${mensaje}</p>
</body>
</html>

Ejemplo de operaciones CRUD con Spring MVC

Controlador para gestionar libros.

package com.ejemplo.controlador;
import com.ejemplo.servicio.LibroServicio;
import com.ejemplo.utilidad.Paginador;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/libro")
public class LibroControlador {
    @Autowired
    private LibroServicio servicioLibro;
    @RequestMapping("/lista")
    public String listar(Map<String, Object> modelo, HttpServletRequest solicitud) {
        Paginador paginador = new Paginador();
        paginador.setSolicitud(solicitud);
        List<Map<String, Object>> libros = servicioLibro.listarPaginado(paginador);
        modelo.put("listaLibros", libros);
        modelo.put("paginador", paginador);
        return "listaLibros";
    }
    @RequestMapping("/prepararFormulario")
    public String prepararFormulario(Integer idLibro, HttpServletRequest solicitud) {
        if (idLibro != null) {
            Map<String, Object> libro = servicioLibro.obtenerPorId(idLibro);
            solicitud.setAttribute("libro", libro);
        }
        return "editarLibro";
    }
    @RequestMapping("/agregar")
    public String agregar(Map<String, Object> libro) {
        servicioLibro.agregar(libro);
        return "redirect:/libro/lista";
    }
    @RequestMapping("/eliminar/{idLibro}")
    public String eliminar(@PathVariable Integer idLibro) {
        servicioLibro.eliminar(idLibro);
        return "redirect:/libro/lista";
    }
    @RequestMapping("/actualizar")
    public String actualizar(Map<String, Object> libro) {
        servicioLibro.actualizar(libro);
        return "redirect:/libro/lista";
    }
}

Vistas JSP para listar y editar libros.

<%-- listaLibros.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>Lista de Libros</title>
    <script>
        function navegarAEditar(id) {
            window.location.href = "${pageContext.request.contextPath}/libro/prepararFormulario?idLibro=" + id;
        }
        function eliminarLibro(id) {
            window.location.href = "${pageContext.request.contextPath}/libro/eliminar/" + id;
        }
    </script>
</head>
<body>
    <button onclick="window.location.href='${pageContext.request.contextPath}/libro/prepararFormulario'">Agregar Libro</button>
    <table border="1">
        <tr><th>ID</th><th>Nombre</th><th>Precio</th><th>Acciones</th></tr>
        <c:forEach items="${listaLibros}" var="libro">
            <tr>
                <td>${libro.idLibro}</td>
                <td>${libro.nombre}</td>
                <td>${libro.precio}</td>
                <td>
                    <button onclick="navegarAEditar(${libro.idLibro})">Editar</button>
                    <button onclick="eliminarLibro(${libro.idLibro})">Eliminar</button>
                </td>
            </tr>
        </c:forEach>
    </table>
    <%-- Componente de paginación omitido por brevedad --%>
</body>
</html>
<%-- editarLibro.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Editar Libro</title>
    <script>
        function enviarFormulario(id) {
            var formulario = document.getElementById("formLibro");
            if (id) {
                formulario.action = "${pageContext.request.contextPath}/libro/actualizar";
            } else {
                formulario.action = "${pageContext.request.contextPath}/libro/agregar";
            }
            formulario.submit();
        }
    </script>
</head>
<body>
    <form id="formLibro" method="post">
        <input type="hidden" name="idLibro" value="${libro.idLibro}">
        <label>Nombre: <input type="text" name="nombre" value="${libro.nombre}"></label><br>
        <label>Precio: <input type="text" name="precio" value="${libro.precio}"></label><br>
        <button type="button" onclick="enviarFormulario('${libro.idLibro}')">Guardar</button>
    </form>
</body>
</html>

Manejo de recursos estáticos en Spring MVC

Para servir archivos como imágenes, CSS o JavaScript, se configura en el archivo XML del servlet.

<mvc:resources location="/recursos-estaticos/img" mapping="/recursos-estaticos/img/**"/>
<mvc:resources location="/recursos-estaticos/css" mapping="/recursos-estaticos/css/**"/>
<mvc:resources location="/recursos-estaticos/js" mapping="/recursos-estaticos/js/**"/>

Los archivos se colocan en la carpeta correspondiente dentro de webapp, por ejemplo, webapp/recursos-estaticos/img/imagen.jpg.

Etiquetas: Spring MVC java jsp maven DispatcherServlet

Publicado el 6-1 13:40