Manejo de Excepciones en SpringMVC (II)

En este tutorial vamos a ampliar la información que detallábamos en Manejo de excepciones en SpringMVC con el uso de @ControllerAdvice y @RestControllerAdvice.

Índice de contenidos

1. Introducción

Las anotaciones @ControllerAdvice y @RestControllerAdvice permiten utilizar las mismas técnicas de manejo de excepciones que veíamos en Manejo de excepciones en SpringMVC pero a nivel de toda la aplicación.

La anotación @ControllerAdvice aparece en la versión 3.2 de Spring y consiste en una especialización de la anotación @Component que permite declarar métodos relacionados con el manejo de excepciones que serán compartidos entre múltiples controladores, evitando así la duplicidad de código o la generación de jerarquías para que los controladores traten de manera homogénea las excepciones.

Por otro lado, la anotación @RestControllerAdvice aparece por primera vez en la versión 4.3 de Spring y se trata de una anotación que aúna @ControllerAdvice y @ResponseBody. Su funcionamiento es prácticamente idéntico a @ControllerAdvice, aunque su uso está enfocado a APIs REST, con el agregado de permitirnos establecer un contenido para el cuerpo de las respuestas los casos de error contemplados.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: MacBook Pro 17′ (2.66 GHz Intel Core i7, 8GB DDR3 SDRAM).
  • Sistema Operativo: Mac OS Sierra 10.12.5
  • Entorno de desarrollo: IntelliJ 2017.1
  • Apache Maven 3.3.9

3. Uso de @ControllerAdvice y @RestControllerAdvice

3.1. @ControllerAdvice

En nuestros proyectos SpringMVC, tan solo será necesario declarar la clase encargada de gestionar las incidencias y anotarla con una de las dos anotaciones, dependiendo del caso, @CotrollerAdvice o @RetControllerAdvice.

Si no se establece lo contrario, la lógica definida para el manejo de una excepción mediante esta herramienta se aplicará de manera global.

Como es de esperar, no siempre querremos aplicar esta solución a la totalidad de los controladores sino a un subconjunto concreto de los mismos. Esta situación tiene fácil solución puesto que podemos acotar su ámbito de aplicación de diferentes maneras:

  • Seleccionando la paquetería base sobre la que queremos que aplique:

  • Seleccionando el conjunto de clases que extiendan una clase o implementen una interfaz:

  • Seleccionando el conjunto de clases anotadas de una manera específica:

Esta anotación da soporte, a su vez, a 3 anotaciones distintas:

  • @ExceptionHandler: Los métodos anotados de esta manera se encargarán de manejar las excepciones que se hayan detallado en la propia anotación.
  • @ModelAttribute: Esta anotación permite completar la información de un modelo expuesto vía web view.
  • @InitBinder: Permite inicializar el WebDataBinder que se utilizará para inicializar los formularios asociados al controlador.

3.2. @RestControllerAdvice

La forma de trabajar es similar a la utilizada con la @ControllerAdvice:

  • Anotamos nuestra clase de manejo general con @RestControllerAdvice.
  • Definimos el método con la lógica de control adecuada y lo anotamos con @ExceptionHandler estableciendo la excepción de la que nos vamos a encargar.
  • Establecemos el código de estado en la respuesta mediante @ResponseStatus.

El método encargado de manejar la excepción debe devolver el objeto con la información relativa a la excepción.

4. Ejemplo de aplicación

Para ilustrar el uso de estas anotaciones vamos a proceder con la creación de un proyecto web con SpringBoot, SpringMVC y Thymeleaf.

Nos ayudaremos de IntelliJ como IDE para realizar el arranque de proyecto, en concreto utilizando el asistente SpringInitialzr.

La imagen anterior muestra la estructura de carpetas resultante tras hacer uso del asistente.

A continuación, como en otras ocasiones, estableceremos las dependencias de nuestro proyecto.

pom.xml

El asistente habrá creado una clase Application por defecto que se ajusta a nuestras necesidades.

DemoApplication.java

Y a continuación detallamos el controlador encargado de manejar las peticiones y la plantilla html para dar forma a nuestra página.

DemoController.java
greeting.html

Con esto ya tenemos la aplicación base sobre la que vamos a establecer nuestro @ControllerAdvice.

Si procedemos con el arranque de la aplicación y consultamos con nuestro navegador la URL adecuada, en nuestro caso http://localhost:8081/greeting podremos ver el sistema funcionando correctamente.

A continuación pasamos a configurar nuestro ControllerAdvice delcarando la clase y su método encargado de manejarlo.

DemoExceptionHandler.javas

Hemos establecido la clase anterior como controladora de excepciones a nivel global mediante @ControllerAdvice, y hemos especificado a través de la anotación @ExceptionHandler(Exception.class) que el método exceptionHandler se encargue de manejar las excepciones de tipo Exception de manera que se muestre la template error.

A continuación definimos la template error.html.

error.html

Por último crearemos un endpoint que tan solo lance la excepción para poder ver que el ControllerAdvice funciona correctamente:

ExceptionGeneratorController.java

5. Conclusiones

Como hemos visto, mediante las anotaciones @ControllerAdvice y @RestControllerAdvice podemos declarar, de una manera rápida y elegante, el comportamiento que debe tener nuestra aplicación cuando se producen excepciones.

6. Referencias