Clases con el La anotación @Controller y @ControllerAdvice pueden tener métodos marcados con la anotación @ExceptionHandler para manejar excepciones de los métodos del controlador, como se muestra en el siguiente ejemplo:

Java

@Controller
public class SimpleController {
    // ...
    @ExceptionHandler
    public ResponseEntity<String> handle(IOException ex) {
        // ...
    }
}
Kotlin

@Controller
class SimpleController {
    // ...
    @ExceptionHandler
    fun handle(ex: IOException): ResponseEntity<String> {
        // ...
    }
}

La excepción puede ser una excepción de alto nivel propagada (por ejemplo, una IOException lanzada directamente.) o una causa anidada dentro de una excepción contenedora (por ejemplo, IOException incluida dentro de una IllegalStateException). A partir de 5.3, esto puede coincidir en niveles de causa arbitrarios, mientras que anteriormente solo se tenía en cuenta la causa inmediata.

Para hacer coincidir tipos de excepción, es preferible declarar la excepción de destino como un argumento de método, como se muestra en el ejemplo anterior. Cuando coinciden varios métodos de exclusión, generalmente se prefiere una coincidencia de exclusión raíz a una coincidencia de exclusión de causa. En particular, ExceptionDepthComparator se utiliza para ordenar excepciones según la profundidad del tipo de excepción lanzada.

Además, una declaración de anotación puede limitar los tipos de excepciones que deben coincidir. , como se muestra en el siguiente ejemplo:

Java

@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
    // ...
}
Kotlin

@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: IOException): ResponseEntity<String> {
    // ...
}

Incluso puedes usar una lista de tipos de excepción específicos con una firma de argumento muy general, como se muestra en el siguiente ejemplo:

Java

@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
    // ...
}
Kotlin

@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: Exception): ResponseEntity<String> {
    // ...
}

La diferencia entre el mapeo de excepción raíz y causa puede sorprender.

En la variante IOException mostrada anteriormente, el método normalmente se llama usando la instancia real FileSystemException o RemoteException como argumento. , ya que ambos se extienden desde IOException. Sin embargo, si dicha excepción coincidente se propaga dentro de una excepción contenedora que es en sí misma una IOException, entonces la instancia de excepción pasada es esa excepción contenedora.

En el identificador handle(Exception)La lógica de funcionamiento es aún más sencilla. Se llama usando una excepción contenedora en el script de envoltura, mientras que la excepción correspondiente real se puede encontrar a través de ex.getCause() en este caso. La excepción pasada es una instancia real de FileSystemException o RemoteException solo si se lanzan como excepciones de alto nivel.

Generalmente es Se recomienda dar la mayor cantidad de opciones posibles en la firma del argumento para reducir la probabilidad de inconsistencia entre los tipos de excepción raíz y de causa. Considere la posibilidad de dividir un método de múltiples visitas en métodos separados anotados con @ExceptionHandler, cada uno de los cuales coincida con un tipo específico de excepción a través de su firma.

En una configuración con múltiples anotaciones @ControllerAdvice Recomendamos declarar asignaciones de excepciones raíz en la anotación @ControllerAdvice en el orden de prioridad adecuado. Aunque se prefiere la coincidencia de excepción raíz a la coincidencia de excepción de causa, la definición se produce entre los métodos de un controlador o clase determinado anotado con @ControllerAdvice. Esto significa que una coincidencia de causa para un bean anotado con @ControllerAdvice con una prioridad más alta se prefiere a cualquier coincidencia (como raíz) para un bean anotado con @ControllerAdvice con una prioridad más baja.

Por último, pero no menos importante, una implementación de un método marcado con la anotación @ExceptionHandler puede negarse a manejar una instancia de excepción determinada al volver a lanzarla en su forma original. . Esto es útil en los casos en los que solo le interesan coincidencias en el nivel raíz o coincidencias en un contexto específico que no se puede determinar estáticamente. El nuevo lanzamiento de la excepción se propaga a lo largo de la cadena de resolución restante como si el método dado con la anotación @ExceptionHandler no coincidiera con el primero.

Soporte para métodos con la anotación@ExceptionHandler en Spring MVC está construida en el nivel DispatcherServlet, el mecanismo HandlerExceptionResolver.

Argumentos del método

Métodos con la anotación @ExceptionHandler admite los siguientes argumentos:

Argumento del método Descripción

Tipo de excepción

Proporciona acceso a la excepción lanzada.

HandlerMethod

Proporciona acceso al controlador de método que lanzó la excepción.

WebRequest, NativeWebRequest

Acceso escrito a los parámetros de solicitud y a los atributos de solicitud y sesión sin uso directo de la API de Servlet.

javax.servlet.ServletRequest, javax.servlet.ServletResponse

Seleccione cualquier tipo de solicitud o respuesta específica (por ejemplo, ServletRequest o HttpServletRequest, o MultipartRequest o MultipartHttpServletRequest de Spring).

javax.servlet.http.HttpSession

Asegura la presencia de una sesión. Como consecuencia, dicho argumento nunca es null.
Tenga en cuenta que el acceso a la sesión no es seguro para subprocesos. Considere establecer el indicador synchronizeOnSession de la instancia RequestMappingHandlerAdapter en true si se permite que varias solicitudes accedan a la sesión simultáneamente.

java.security.Principal

El archivo autenticado actual usuario: posiblemente una clase de implementación concreta de Principal, si se conoce.

HttpMethod

Método de solicitud HTTP.

java.util.Locale

La configuración regional actual de la solicitud, determinada por el LocaleResolver más específico disponible; esencialmente el LocaleResolver o configurado LocaleContextResolver.

java.util.TimeZone, java.time.ZoneId

La zona horaria asociada con la solicitud actual, según lo determinado por LocaleContextResolver.

java.io.OutputStream, java.io.Writer

Proporciona acceso al cuerpo de la respuesta sin formato, ya que lo proporciona la API de Servlet.

java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap

Proporciona acceso al modelo para proporcionar una respuesta de error. Siempre vacío.

RedirectAttributes

Establecer los atributos utilizados en el caso de una redirección - (que se agregará a la cadena de solicitud) y atributos flash para almacenamiento temporal hasta que la solicitud llegue después de la redirección.

@SessionAttribute

Diseñado para proporcionar acceso a cualquier atributo de sesión, a diferencia de los atributos del modelo, almacenados en la sesión como resultado de declarar el @SessionAttributes anotación a nivel de clase.

@RequestAttribute

Diseñado para proporcionar acceso a los atributos de solicitud.

Valores de retorno

Métodos con la anotación @ExceptionHandler admite los siguientes valores de retorno:

Valor de retorno Descripción

@ResponseBody

El valor de retorno se convierte a través de instancias HttpMessageConverter y se escribe en la respuesta.

HttpEntity<B>, ResponseEntity<B>

El valor de retorno especifica que la respuesta completa (incluidos los encabezados y el cuerpo HTTP) se convertirá a través de instancias HttpMessageConverter y se escribirá en la respuesta.

String

El nombre de la vista que debe ser reconocida por implementaciones de ViewResolver y se usa junto con un modelo implícito, definido a través de objetos y métodos de comando con la anotación @ModelAttribute. El método controlador también puede modificar el modelo mediante programación declarando un argumento Model (descrito anteriormente).

View

Una instancia de View destinada a ser representada junto con un modelo implícito, definido a través de objetos y métodos de comando con la anotación @ModelAttribute. Un método controlador también puede modificar un modelo mediante programación declarando un argumento Model (descrito anteriormente).

java.util.Map, org.springframework.ui.Model

Atributos para agregar al modelo implícito con el nombre de la vista implícitamente definido a través de RequestToViewNameTranslator.

@ModelAttribute

Un atributo agregado al modelo con el nombre de la vista definido implícitamente mediante RequestToViewNameTranslator.

Tenga en cuenta que la anotación @ModelAttribute es opcional. Consulte la sección "Cualquier otro valor de retorno" al final de esta tabla.

ModelAndView objeto

Los atributos de vista y modelo a utilizar y, si es necesario, el estado de la respuesta.

void

Se considera que un método con un tipo de retorno void (o un valor de retorno null) habrá procesado completamente la respuesta si también tiene el argumento ServletResponse o OutputStream, o la anotación @ResponseStatus. Lo mismo ocurre si el controlador ha realizado una verificación positiva de la marca de tiempo ETag o lastModified.

Si ninguna de las opciones anteriores es verdadera, el tipo de devolución es void también puede indicar "sin cuerpo de respuesta" para controladores REST o una opción de nombre de vista predeterminada para controladores HTML.

Cualquier otro valor de retorno

Si el valor de retorno no coincide con ninguno de los anteriores y no es un tipo primo (como se define en BeanUtils#isSimpleProperty), por defecto se considera un atributo del modelo que debe agregarse al modelo. Si es un tipo simple, entonces permanece sin resolver.

Tratamiento de excepciones en la API REST

A El requisito común para los servicios REST es incluir información de error en el cuerpo de la respuesta. Spring Framework no hace esto automáticamente, ya que la presentación de información de error en el cuerpo de la respuesta es específica de la aplicación. Sin embargo, la anotación @RestController puede usar métodos marcados con la anotación @ExceptionHandler con un valor de retorno ResponseEntity para establecer el estado y el cuerpo de la respuesta. Estos métodos también se pueden declarar en clases anotadas con @ControllerAdvice para que puedan aplicarse globalmente.

Las aplicaciones que implementan el manejo global de excepciones con una descripción detallada del error en el cuerpo de la respuesta deben considere el objetivo extensible ResponseEntityExceptionHandler, que maneja las excepciones lanzadas en Spring MVC y proporciona interceptores para personalizar el cuerpo de la respuesta. Para aprovechar esto, cree una subclase de ResponseEntityExceptionHandler, anótalo con @ControllerAdvice, anula los métodos necesarios y declaralo como un Spring Bean.