Spring MVC es un framwork diseñado para desacoplar la lógica de presentación de la lógica de negocio en aplicaciones web Java, optimizando la gestión de Servlets de manera análoga a cómo MyBatis simplifica la capa DAO o Spring Core la capa de servicios. Actualmente, se posiciona como el estándar frente a alternativas como Struts o JFinal.
Configuración Mediante Archivos XML
En el modelo tradicional, el flujo se define a través de archivos de configuración. Primero, es necesaroi definir el controlador en un archivo, por ejemplo, web-mvc-config.xml.
<!-- Definición del controlador en el contexto de Spring -->
<bean id="/loginAction" class="com.app.web.LoginController" />
El controlador debe implementar la interfaz Controller y retornar un objeto ModelAndView:
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class LoginController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("usuarioActivo", "Admin");
mv.setViewName("dashboard.jsp");
return mv;
}
}
Posteriormente, se configura el DispatcherServlet en el archivo web.xml para actuar como el front-controller de la aplicación:
<servlet>
<servlet-name>appDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>appDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Desarrollo Basado en Anotaciones
La evolución del framwork permite prescindir de la implementación forzosa de interfaces mediante el uso de anotaciones. Para habilitar esto, se debe configurar el escaneo de componentes en el XML de Spring:
<!-- Escaneo de clases anotadas -->
<context:component-scan base-package="com.app.controllers" />
<!-- Activación de controladores de anotaciones, validación y soporte JSON -->
<mvc:annotation-driven />
Uso de @Controller y @RequestMapping
Las anotaciones permiten definir rutas de acceso y el ciclo de vida del componente. Con @Scope("prototype"), se garantiza que se cree una nueva instancia por cada petición.
@Controller
@RequestMapping("/inventario")
public class ProductoController {
@RequestMapping("/lista")
public String listarProductos(Model modelo) {
modelo.addAttribute("items", Arrays.asList("Laptop", "Monitor"));
return "productos/vistas/lista";
}
@RequestMapping("/detalles")
public String verDetalle(HttpServletRequest req) {
req.setAttribute("msg", "Datos cargados desde Request");
return "productos/detalle";
}
}
Gestión de Parámetros de Entrada
Spring MVC ofrece múltiples mecanismos para capturar datos enviados por el cliente:
- Captura Individual: Vinculación directa por nombre de parámetro.
- Objetos POJO: Mapeo automático de campos de formulario a atributos de un objeto.
- RESTful: Uso de
@PathVariablepara extraer datos de la URL. - JSON: Uso de
@RequestBodyjunto con Jackson para deserializar datos.
@RequestMapping("/api/v1/auth/{rol}")
public String autenticar(
@PathVariable String rol,
@RequestParam("token") String jwt,
UserDTO usuario) {
// Lógica de procesamiento
return "success";
}
Codificación y Seguridad de Recursos
Para evitar problemas con caracteres especiales, se recomienda el uso de un filtro de codificación en el web.xml:
<filter>
<filter-name>encodingFilter</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>
Es una práctica estándar colocar los archivos JSP dentro del directorio /WEB-INF/. Esto impide que los usuarios accedan directamente a las vistas, forzando el paso a través del controlador.
Resolución de Vistas
El InternalResourceViewResolver automatiza la búsqueda de plantillas añadiendo prefijos y sufijos a los nombres retornados por los métodos.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/vistas/" />
<property name="suffix" value=".jsp" />
</bean>
Carga y Descarga de Archivos
Para procesar archivos, se requiere el bean multipartResolver y configurar el formulario con enctype="multipart/form-data".
@RequestMapping("/upload")
public String procesarArchivo(MultipartFile adjunto) throws IOException {
if (!adjunto.isEmpty()) {
File destino = new File("/storage/uploads/", adjunto.getOriginalFilename());
adjunto.transferTo(destino);
}
return "status_ok";
}
Jerarquía de Contenedores
En aplicaciones complejas, Spring opera con una estructura de padre e hijo. El Contexto Padre (cargado vía ContextLoaderListener) suele contener servicios y DAOs. El Contexto Hijo (específico del DispatcherServlet) contiene controladores y resolutores de vistas. El hijo puede acceder a los beans del padre, pero no a la inversa.
Pools de Conexiones: DBCP vs C3P0
Al integrar Spring con bases de datos, la elección del pool de conexiones es crítica:
- DBCP (Apache): Se enfoca en gestionar un número máximo de conexiones. Si se excede, las conexiones se cierran. Es conocido por su alta velocidad de ejecución.
- C3P0: Implementa una gestión basada en el tiempo de inactividad (idle time). Desconecta automáticamente los enlaces que superan el tiempo de espera. Posee mecanismos de recuperación automática más robustos, aunque puede ser ligeramente más lento que DBCP.