Introducción a Aplicaciones REST con Spring 3.0 Web MVC Framework

El Framework Web MVC (modelo-vista-controlador) de Spring está diseñado alrededor de un Servlet (DispatcherServlet) encargado de enviar las peticiones a los diferentes manejadores (handlers) de la aplicación, a partir de la configuración del mapeo de manejadores, la resolución de las vistas, locale, etc. Es decir, al configurar este serlvet en el fichero web.xml de tu aplicación web, todas las peticiones pasarán por él y se encargará de redirigir a los diferentes manejadores. Los manejadores por defecto se basan en las anotaciones @Controller y @RequestMapping como veremos a continuación. A partir de la versión 3.0 de Spring es posible crear aplicaciones Web RESTfull a través de la anotación @PathVariable.

En esto último se va a centrar este artículo, en la implementación de los controladores a través de anotaciones y en la configuración de los mismos para crear aplicaciones REST.

Dispatcher Servlet

Cómo comentamos al principio, el framework MVC de Spring está diseñado alrededor de un servlet que reenvía las peticiones a los diferentes controladores. Este servlet está plenamente integrado con el contenedor IoC (Inversion of Control) lo que permite usar todas las características del framework Spring.

Workflow del Servlet

Se trata de un servlet (hereda de la clase base HttpServlet) y como tal se declara en el fichero de configuración web.xml de tu aplicación web:

<web-app>

    <servlet>
        <servlet-name>buscar</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>buscar</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

</web-app>

En el ejemplo anterior, tal como se puede ver en el mapeo del servlet, todas las peticiones que acaben en .do serán manejados por el DispatcherServlet buscar.

En el framework Web MVC cada DispatcherServlet tiene asociado su propio WebApplicactionContext, el cuál hereda todos los beans definidos en el WebApplicationContext raíz que pueden ser sobreescritos. Una vez inicializado el DispatcherServlet, el framework busca un fichero llamado [servlet-name]-servlet.xml en el directorio WEB-INF de tu aplicación web y crea los beans allí definidos (si hay beans con el mismo nombre que los del contexto raíz los sobreescribe). En el ejemplo anterior debemos tener un fichero llamado buscar-servlet.xml.

El DispatcherServlet de Spring usa beans especiales para procesar las peticiones y mostrar las vistas apropiadas. Estos beans son parte del Framework y pueden ser configurados en el contexto WebApplicationContext como harías con otros beans. Sin embargo, para la mayoría de los beans se proporcionan parámetros por defecto y no necesitan configuración.

Contexto del DispatcherSerlvet

Implementando Controladores

Los controladores proveen acceso al comportamiento de la aplicación, interpretan los inputs del usuario y los transforman en un modelo que es representado al usuario por una vista (modelo-vista-controlador). Spring implementa un controller de una manera abstracta, lo que permite crear una gran variedad de controladores.

A partir de la versión 2.5, y la mantiene también en la versión 3.0, Spring introdujo el modelo de programación basado en anotaciones, que usa anotaciones como @RequestMapping, @RequestParam, @ModelAttribute, etc. Los controladores implementados a través de este estilo no necesitan heredar de ninguna clase base o implementar ninguna interfaz específica:

@Controller
public class HelloWorldController {

    @RequestMapping("/helloWorld")
    public ModelAndView helloWorld() {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("helloWorld");
        mav.addObject("message", "Hello World!");
        return mav;
    }
}

Definiendo un controlador con @Controller

La anotación @Controller indica que una clase tendrá el rol Controlador. No se requiere heredar de ninguna clase base o del API de Servlet, como ocurría en la versión 2.0. El Dispatcher busca las clases “marcadas” con dicha anotación para mapear los métodos y detectar todas las anotaciones @RequestMapping (ver más abajo).

Para activar la autodetección de los controllers que contienen la anotación, debes añadir a tu configuración el componente que los escanea:

<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.paquete.ejemplo.controllers"/>

    // ...

</beans>

Mapeando peticiones con @RequestMapping

Se usa la anotación @RequestMapping para mapear URLs como por ejemplo “/mostrareventos” con una clase, o bien un método dentro de la clase. Si es a nivel de clase, se suele mapear una URL concreta con métodos adicionales que acotan el mapeo a través de métodos HTTP específicos (POST, GET, etc.) o bien mediante parámetros en la petición.

@Controller
@RequestMapping("/mostrareventos")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;

    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Map<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();
    }

    @RequestMapping(value="/{dia}", method = RequestMethod.GET)
    public Map<String, Appointment> getForDay(
                @PathVariable @DateTimeFormat(iso=ISO.DATE) Date dia,
                Model model) {
        return appointmentBook.getAppointmentsForDay(dia);
    }

    @RequestMapping(value="/new", method = RequestMethod.GET)
    public AppointmentForm getNewForm() {
        return new AppointmentForm();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String add(@Valid AppointmentForm evento,
                       BindingResult result) {
        if (result.hasErrors()) {
            return "mostrareventos/new";
        }
        appointmentBook.addAppointment(evento);
        return "redirect:/mostrareventos";
    }
}

En el ejemplo anterior la anotación @RequestMapping se usa primero a nivel de clase. De esa manera indica que todos los métodos de este controlador manejarán las peticiones con el path relativo “/mostrareventos”. El métdo get() refina dicha URL y se ejecuta únicamente cuando se trata de un método GET. El método add(), por el contrario, se ejecuta cuando se realiza un POST de un formulario del sitio web.

Los métodos getForDay() y getNewForm() se ejecutarán cuando se trate de una petición GET y además la URL contenga “/mostrareventos/díaEventoo “/mostrareventos/new”, respectivamente.

URI Templates

Para acceder a partes de la URL en los métodos manejadores usamos los patrones de URI o URI Templates, dando valores dentro del path de @RequestMapping. Luego podemos usar la anotación @PathVariable para indicar que un parámetro del método se va a enlazar con un valor que viene en una variable de la URI. Veamos un ejemplo:

@RequestMapping(value="/alumnos/{alumnoId}", method=RequestMethod.GET)
public String findAlumno(@PathVariable String alumnoId, Model model) {
  Alumno alumno = alumnoService.findAlumno(alumnoId);
  model.addAttribute("alumno", alumno);
  return "displayAlumno";
}

La URI Template “/alumnos/{alumnoId}” especifica la variable con el nombre alumnoId. Cuando un controlador maneja esta petición, el valor de alumnoId se establece con el valor que viene en la URL. Por ejemplo, cuando llega una petición con esta URL “/alumnos/francisco” el valor “francisco” se asociará al parámetro alumnoId de tipo String del método manejador.

Puedes usar varias anotaciones @PathVariable para enlazar múltiples variables URI Templates:

@RequestMapping(value="/alumno/{alumnoId}/asignatura/{asignaturaId}",
                 method=RequestMethod.GET)
public String findAsignatura(@PathVariable String alumnoId,
                 @PathVariable String asignaturaId, Model model) {
  Alumno alu = alumnoService.findAlumno(alumnoId);
  Asignatura asig = alumno.getSignatura(signaturaId);
  model.addAttribute("Asignatura", asignatura);
  return "displayAsignatura";
}

El método findAsignatura se ejecutaría al invocar, por ejemplo la URL “/alumno/245/asignatura/32“. Podemos indicar una parte a nivel de clase y otra a nivel de método como en el siguiente ejemplo:

@Controller
@RequestMapping("/alumno/{alumnoId}")
public class RelativePathUriTemplateController {

  @RequestMapping("/asignatura/{asignaturaId}")
  public void findPet(@PathVariable String alumnoId,
                       @PathVariable String asignaturaId,
                         Model model) {
    // implementación omitida
  }
}

Conclusiones

Tal y cómo nos propusimos al inicio de este artículo pretendíamos realizar una introducción a la programación de aplicaciones REST con Spring 3.0. Cómo cualquier aplicación Spring MVC, hemos configurado el DispatcherServlet, hemos aprendido a declarar controladores mediante la anotación @Controller. También hemos mapeado peticiones con la anotación @RequestMapping y por último hemos asociado valores de variables de la URL a parámetros de los métodos manejadores de los controladores mediante URI Templates y la anotación @PathVariable. Con todo esto podemos comenzar a construir una aplicación REST en la que cada recurso sea accesible mediante una URL amigable del tipo:

http://mi-dominio/gestionalumnos/
http://mi-dominio/gestionalumnos/alumno/new
http://mi-dominio/gestionalumnos/alumno/234
http://mi-dominio/gestionalumnos/alumno/234/asignatura/32
http://mi-dominio/gestionalumnos/asignatura/new
http://mi-dominio/gestionalumnos/asignatura/32
etc...

Este artículo está basado en la documentación de referencia de Spring. Para ampliar estos y otros temas puedes consultar la Referencia del framework Spring MVC.

3 opiniones en “Introducción a Aplicaciones REST con Spring 3.0 Web MVC Framework”

  1. Yo también tengo el mismo problema que Kenny Rodas Chavez. Tengo el controlador implementado de está manera:
    @RequestMapping(value=”/web/white.htm”, method = RequestMethod.GET)
    public @ResponseBody String getInformacion(@RequestParam(value = “estado_rec”) String estado_rec) {

    Al pasar el parámetro desde Ajax, me da el siguiente error:
    request parameter “estado_rec” is required.

    Gracias de antemano por la ayuda

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *