Spring Web MVC es un framework de desarrollo web que forma parte de Spring framework. Está basado en el Patrón MVC. Utiliza un enfoque basado en convenciones para que el desarrollo sea más fácil. Aprovecha las funciones propias de Spring como IoC (Inversion of Control) y DI (Dependency Inyection).
Mediante una serie de anotaciones y clases permite la configuración y el enrutamiento de solicitudes HTTP de forma automática. Otras características reseñables son el manejo de excepciones, la validación de formularios y la internacionalización.
1. Patrón MVC
El patrón MVC (Model-View-Controller) es un patrón de diseño arquitectónico muy utilizado, sobre todo en aplicaciones web. Como su nombre indica, se compone de tres componentes (o capas):
- Modelo: contiene la lógica de la aplicación, realizando cálculos, aplicando reglas de negocio e interactuando con la capa de acceso a datos. La vista hace uso de esta capa.
- Vista: consiste en la UI (interfaz de usuario) de la aplicación. Muestra la información en pantalla con la que interactúa el usuario. El modelo proporciona dichos datos. Esta capa no contiene lógica de negocio.
- Controlador: articula la comunicación entre las capas del modelo y la vista. Le llegan las interacciones del usuario en pantalla, actualizando el modelo.
A continuación se muestra un diagrama de secuencia mostrando como funciona el patrón MVC:
Cada capa tiene una responsabilidad diferente, consiguiendo una mayor modularidad, reutilización y mantenibilidad. Así cada componente puede ser modificado o reemplazado de manera independiente.
2. Anotaciones Controller y RestController
Para crear un componente de la capa controlador en Spring se usan dos anotaciones: @Controller y @RestController. La principal diferencia entre ellas es el tipo de respuestas de cada una, como veremos más adelante. Se definen como:
- @Controller: indica que la clase es un controlador. Sirve para aplicaciones web tradicionales, devolviendo una vista HTML. Los métodos dentro de esta clase mapean diferentes URLs utilizando @RequestMapping (o sus variantes específicas @GetMapping, @PostMapping, etc.) y devuelven objetos ModelAndView o un String con la vista a presentar.
- @RestController: combina la anotación anterior junto con @ResponseBody. Maneja solicitudes HTTP y devuelve datos en lugar de HTML. Por defecto los datos se serializan en el formato JSON, aunque se puede personalizar, al igual que la cabecera o los códigos de estado.
En la siguiente tabla se comparan las diferentes características de ambas anotaciones:
Característica | @Controller | @RestController |
Tipo de respuesta | Devuelve vistas HTML o ModelAndView | Devuelve datos (generalmente en formato JSON) |
Conversión automática de datos | No | Sí |
Uso de anotaciones | Sí (@RequestMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping) | Sí (las mismas) |
Uso de @ResponseBody | Requiere utilizar @ResponseBody en los métodos individuales | No es necesario utilizar @ResponseBody |
Serialización de datos | No | Sí. Por defecto, los datos se serializan en formato JSON |
Personalización de respuestas | Se utiliza ModelAndView y métodos para configurar vistas | Se utiliza @ResponseEntity para personalizar la respuesta |
3. Creación de un Controller con Spring Web MVC
A continuación crearemos un ejemplo sencillo de Controller con Spring. Primero tenemos que configurar las dependencias de Spring Web MVC. Como usaremos Maven, tendremos que definirlas en el pom.xml:
<dependencies> <!-- Dependencias de Spring Web MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.0.9</version> </dependency> <!-- Otras dependencias --> ... </dependencies>
Ahora podemos crear el Controller marcando la clase como tal:
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class SaludoController { @GetMapping("/") public String saludo(Model model) { String saludoSamurai = "¡Hola samurái!"; model.addAttribute("saludo", saludoSamurai); return "home"; } }
El método saludo está mapeado con la URL raíz (‘/’) utilizando la anotación @GetMapping para realizar un GET de HTTP. Dentro del método se añade un atributo saludo con la variable saludoSamurai para que sea accesible desde la vista. Al final retorna la vista, en este caso llamada home, que será una página JSP como sigue:
<!-- Archivo home.jsp --> <!DOCTYPE html> <html> <head> <title>Spring MVC Example</title> </head> <body> <h1>${saludo}</h1> </body> </html>
Mediante ${saludo} mostramos el saludo definido en el método saludo del Controller. Por último queda configurar Spring Web MVC con una clase de configuración:
// Archivo WebConfig.java import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp("/WEB-INF/views/", ".jsp"); } }
La anotación @EnableWebMvc indica que nuestra aplicación hará uso de Spring Web MVC. El método configureViewResolvers se encarga de indicar donde se encuentran las vistas y que extensión tendrán. En el caso del ejemplo, al retornar «home», irá a buscar la página JSP en /WEB-INF/views/home.jsp.
Se pueden añadir mejoras como:
- Obtener por parámetro, mediante la anotación @RequestParam, el nombre a quién saludar
- La URL mapeada por el método saludo no sea la raíz (‘/’) sino algo más específico como saludar, quedando la anotación @GetMapping(«/saludar»).
4. Creación de un RestController en Spring
Una vez hemos visto como crear un @Controller en Spring Web MVC, ahora veremos como crear un @RestController. En este caso devolverá un objeto JSON en lugar de una vista. Primero tenemos que configurar las dependencias de Spring Web MVC, añadiendo las siguientes líneas con respecto del ejemplo anterior:
<!-- Archivo pom.xml --> <dependencies> ... <!-- Dependencia de Jackson para la serialización y deserialización JSON --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.0</version> </dependency> <!-- Otras dependencias --> ... </dependencies>
Ahora crearemos la clase anotada como @RestController la cual recibe peticiones entrantes y devuelve los datos en un objeto JSON:
// Importa las clases necesarias import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api") public class SamuraiController { @GetMapping("/samurais") public List<User> getSamurais() { List<Samurai> samuraiList = new ArrayList<>(); // Lógica para obtener la lista de samuráis return samuraiList; } }
El método getUsers anotado con @GetMapping responde a solicitudes HTTP GET en la ruta (o path) /samurais. Usa la clase Samurái como POJO y es el objeto que se rellena mediante el Service y el Controlador lo devuelve convertido de manera automática en formato JSON:
@Data @AllArgsConstructor public class Samurai { private String name; private int age; }
Para probarlo se pueden utilizar herramientas específicas para llamar a API, como Postman, o directamente desde el navegador. En el ejemplo que nos ocupa, si ejecutamos el código y ponemos la URL http://localhost:8080/api/samurais, debería devolver el JSON con la lista de Samuráis.
5. Conclusión
En este artículo hemos visto como de una manera sencilla se puede crear un ejemplo básico de uso de un Controller y RestController con Spring Web MVC.