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:
@Controller
public class SimpleController {
// ...
@ExceptionHandler
public ResponseEntity<String> handle(IOException ex) {
// ...
}
}
@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:
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
// ...
}
@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:
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
// ...
}
@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. |
|
Proporciona acceso al controlador de método que lanzó la excepción. |
|
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. |
|
Seleccione cualquier tipo de solicitud o respuesta específica (por ejemplo, |
|
Asegura la presencia de una sesión. Como consecuencia, dicho argumento nunca es |
|
El archivo autenticado actual usuario: posiblemente una clase de implementación concreta de |
|
Método de solicitud HTTP. |
|
La configuración regional actual de la solicitud, determinada por el |
|
La zona horaria asociada con la solicitud actual, según lo determinado por
|
|
Proporciona acceso al cuerpo de la respuesta sin formato, ya que lo proporciona la API de Servlet. |
|
Proporciona acceso al modelo para proporcionar una respuesta de error. Siempre vacío. |
|
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. |
|
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 |
|
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 |
---|---|
|
El valor de retorno se convierte a través de instancias |
|
El valor de retorno especifica que la respuesta completa (incluidos los encabezados y el cuerpo HTTP) se
convertirá a través de instancias |
|
El nombre de la vista que debe ser reconocida por implementaciones de |
|
Una instancia de |
|
Atributos para agregar al modelo implícito con el nombre de la vista implícitamente definido a través de
|
|
Un atributo agregado al modelo con el nombre de la vista definido implícitamente mediante Tenga en cuenta que la anotación |
|
Los atributos de vista y modelo a utilizar y, si es necesario, el estado de la respuesta. |
|
Se considera que un método con un tipo de retorno Si ninguna de las opciones anteriores es verdadera, el tipo de devolución es |
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.