martes, 18 de agosto de 2009

Spring MVC Usando Controllers con Anotaciones

Veamos como podemos implementar una pequeña aplicación en Spring que use SpringMVC con anotaciones de la manera más fácil posible.

Aquí estan los componentes:

1. Descriptor de despliegue(web.xml):
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!--
Declaración del servlet que Spring utilizará como Front Controller
para nuestra aplicación.
-->
<servlet>
<servlet-name>frontController</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Mapping del servlet anterior-->
<servlet-mapping>
<servlet-name>frontController</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

<!--Tiempo en minutos que dura una session -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>

<!--Listado de archivos de bienvenida -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

</web-app>

2. Front Controller de SpringMVC(frontController-servlet.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<!--
La siguiente declaración buscará todos los estereotipos(Clases declaradas
con las anotaciones @Service,@Component,@Controller,@Repository)
en el paquete pe.com.slcsccy.springmvc.controllers una vez identificado el
estereotipo entonces el contenedor instanciará el bean y por lo tanto estará
listo para ser utilizado por la aplicación
-->
<context:component-scan base-package="pe.com.slcsccy.springmvc.controllers"/>
<!--
El siguiente bean configura las propiedades prefijo(prefix) y sufijo(suffix)
de Internalresourceviewresolver, el cual resuelve nombres de vistas lógicas
retornadas por los controladores(en el ejm:clases en el paquete controllers)
Por ejemplo, un nombre de vista lógico podría ser "resultadoPlanillaQuinta"
entonces esta vista será mapeada a "/WEB-INF/jsp/resultadoPlanillaQuinta.jsp"
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
</beans>


3. Un Controller de la aplicación(PlanillaController.java) que mapeará las solicitudes a métodos en esta clase:

package pe.com.slcsccy.springmvc.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class PlanillaController {


/*
Si el método en el controller esta mapeado pero no retorna nada, entonces
Spring lo que hará es buscar una vista con el mismo nombre que el patron
del mapping pero sin la extensión, es decir buscara un archivo jsp con el
siguiente nombre: iniciarApp.jsp, este archivo debe de estar en /WEB-INF/jsp/
*/
@RequestMapping("/iniciarApp.do")
public void iniciarAplicacion() {
System.out.println("Inicio de la aplicación.");
}

/*
El siguiente método acepta todas las solicitudes que vienen del patrón URL(en realidad es una ruta directa) /planilla/procesar.do,este patrón lo declaramos en la anotaciòn @RequestMapping, como salida tenemos un nombre de vista que va estar relacionado a un resolvedor de vistas, quién resolverá el recurso(archivo jsp) a presentar.
*/
@RequestMapping("/planilla/procesarQuinta.do")
public String procesarQuinta(@RequestParam("periodo") String periodo, ModelMap modelo) {
modelo.addAttribute("periodo", periodo);
return "planilla/resultadoPlanillaQuinta";
}

@RequestMapping("/planilla/procesarCuarta.do")
public String procesarCuarta(@RequestParam("periodo") String periodo, ModelMap modelo) {
modelo.addAttribute("periodo", periodo);
return "planilla/resultadoPlanillaCuarta";
}


/*
Este método difiere con los 2 anteriores en el tipo de retorno, ahora el
tipo de retorno no es una cadena sino un ModelMap, este modelMap debe
contener el modelo de datos a ser presentado en la vista, en los métodos
anteriores colocabamos el modelMap como un argumento al método y después
usabamos ese modelMap para colocar atributos(modelo de datos) que iban
a ser pintados en la vista. En este método la vista es resuelta hacia el
mismo URL que lo solicitó, es decir la vista se resuelve hacia:
/WEB-INF/jsp/planilla/cierre.jsp, recordar que el prefijo: WEB-INF/jsp/
y el sufijo son declarados en el frontController:
frontController-servlet.xml, ModelMap si revisas las fuentes de Spring extiende
LinkedHashMap que es una forma especializada de HashMap
*/
@RequestMapping("/planilla/cierre.do")
public ModelMap cerrarPlanilla(@RequestParam("periodo") String periodo) {
/*Aquí consulta compleja a la base de datos para sacar los nombres*/
String[] nombres = {"Carlos","Alberto","Cacique","Yupanqui"};
return new ModelMap("nombres",nombres);
}
}

4. Ahora solo veamos los archivos jsp:
4.1 cierre.jsp (/WEB-INF/jsp/planilla/cierre.jsp)
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Cierre de Planilla</title>
</head>
<body>
<br><br>Planilla Cerrada<br><br>
<table>
<c:forEach var="nombre" items="${nombres}" varStatus="status">
<tr>
<td>${status.index}</td>
<td>${nombres[status.index]}</td>
</tr>
</c:forEach>
</table>
</body>
</html>

4.2 resultadoPlanillaCuarta.jsp (/WEB-INF/jsp/planilla/resultadoPlanillaCuarta.jsp)
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Resultado planilla Cuarta</title>
</head>
<body>
La planilla fue procesada para el periodo ${periodo}
</body>
</html>

4.2 resultadoPlanillaQuinta.jsp (/WEB-INF/jsp/planilla/resultadoPlanillaQuinta.jsp)
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Resultado planilla Quinta</title>
</head>
<body>
La planilla fue procesada para el periodo ${periodo}
</body>
</html>

El desarrollo de esta pequeña aplicación fué realizada con Spring 2.5.6, y el propósito es ver como podemos usar anotaciones en la capa de control de una aplicación MVC. Las anotaciones vistas fueron @Controller y @RequestMapping.

Podemos ver como las solicitudes que enviamos a la aplicació se mapean correctamente probando de la siguiente manera, en el URL de tu navegador puedes poner:


y debería ejecutar el método adecuado sgún el mapping y redirigirse a la vista apropiada.


2 comentarios:

  1. Muy buen tutorial.
    Sigo estos post.
    Espero que puedas publicar realizando algo de Crud de un usuario.
    RequesMapping con get o post
    Saludos
    Desde Argentina

    ResponderBorrar
  2. excelente blog =D
    Solo un par de detalles..

    No funcionan:
    http://://planilla/cierre.do?periodo=200908
    http://://planilla/procesarQuinta.do?periodo=200908

    Seria bueno colocar las clases en un div con diferente color para que se aprecie mejor

    ResponderBorrar

Es bueno comunicarnos, comenta!!.