[doc] Update Spring MVC exception handling content
Issue: SPR-16394
This commit is contained in:
parent
d9a93f44ae
commit
0ded239453
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -60,22 +60,84 @@ import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
|
||||||
* <p>This exception resolver is enabled by default in the common Spring
|
* <p>This exception resolver is enabled by default in the common Spring
|
||||||
* {@link org.springframework.web.servlet.DispatcherServlet}.
|
* {@link org.springframework.web.servlet.DispatcherServlet}.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* <table>
|
||||||
|
* <caption>Supported Exceptions</caption>
|
||||||
|
* <thead>
|
||||||
|
* <tr>
|
||||||
|
* <th class="colFirst">Exception</th>
|
||||||
|
* <th class="colLast">HTTP Status Code</th>
|
||||||
|
* </tr>
|
||||||
|
* </thead>
|
||||||
|
* <tbody>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>HttpRequestMethodNotSupportedException</p></td>
|
||||||
|
* <td><p>405 (SC_METHOD_NOT_ALLOWED)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="rowColor">
|
||||||
|
* <td><p>HttpMediaTypeNotSupportedException</p></td>
|
||||||
|
* <td><p>415 (SC_UNSUPPORTED_MEDIA_TYPE)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>HttpMediaTypeNotAcceptableException</p></td>
|
||||||
|
* <td><p>406 (SC_NOT_ACCEPTABLE)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="rowColor">
|
||||||
|
* <td><p>MissingPathVariableException</p></td>
|
||||||
|
* <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>MissingServletRequestParameterException</p></td>
|
||||||
|
* <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="rowColor">
|
||||||
|
* <td><p>ServletRequestBindingException</p></td>
|
||||||
|
* <td><p>400 (SC_BAD_REQUEST)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>ConversionNotSupportedException</p></td>
|
||||||
|
* <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="rowColor">
|
||||||
|
* <td><p>TypeMismatchException</p></td>
|
||||||
|
* <td><p>400 (SC_BAD_REQUEST)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>HttpMessageNotReadableException</p></td>
|
||||||
|
* <td><p>400 (SC_BAD_REQUEST)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="rowColor">
|
||||||
|
* <td><p>HttpMessageNotWritableException</p></td>
|
||||||
|
* <td><p>500 (SC_INTERNAL_SERVER_ERROR)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>MethodArgumentNotValidException</p></td>
|
||||||
|
* <td><p>400 (SC_BAD_REQUEST)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="rowColor">
|
||||||
|
* <td><p>MissingServletRequestPartException</p></td>
|
||||||
|
* <td><p>400 (SC_BAD_REQUEST)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>BindException</p></td>
|
||||||
|
* <td><p>400 (SC_BAD_REQUEST)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="rowColor">
|
||||||
|
* <td><p>NoHandlerFoundException</p></td>
|
||||||
|
* <td><p>400 (SC_NOT_FOUND)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr class="altColor">
|
||||||
|
* <td><p>AsyncRequestTimeoutException</p></td>
|
||||||
|
* <td><p>503 (SC_SERVICE_UNAVAILABLE)</p></td>
|
||||||
|
* </tr>
|
||||||
|
* </tbody>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
|
* @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
|
||||||
* @see #handleHttpRequestMethodNotSupported
|
|
||||||
* @see #handleHttpMediaTypeNotSupported
|
|
||||||
* @see #handleMissingServletRequestParameter
|
|
||||||
* @see #handleServletRequestBindingException
|
|
||||||
* @see #handleTypeMismatch
|
|
||||||
* @see #handleHttpMessageNotReadable
|
|
||||||
* @see #handleHttpMessageNotWritable
|
|
||||||
* @see #handleMethodArgumentNotValidException
|
|
||||||
* @see #handleMissingServletRequestParameter
|
|
||||||
* @see #handleMissingServletRequestPartException
|
|
||||||
* @see #handleBindException
|
|
||||||
*/
|
*/
|
||||||
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
|
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ import org.springframework.web.util.UriUtils;
|
||||||
* <td><p>acceptCharset</p></td>
|
* <td><p>acceptCharset</p></td>
|
||||||
* <td><p>false</p></td>
|
* <td><p>false</p></td>
|
||||||
* <td><p>true</p></td>
|
* <td><p>true</p></td>
|
||||||
* <td><p><p>Specifies the list of character encodings for input data that is accepted
|
* <td><p>Specifies the list of character encodings for input data that is accepted
|
||||||
* by the server processing this form. The value is a space- and/or comma-delimited
|
* by the server processing this form. The value is a space- and/or comma-delimited
|
||||||
* list of charset values. The client must interpret this list as an exclusive-or
|
* list of charset values. The client must interpret this list as an exclusive-or
|
||||||
* list, i.e., the server is able to accept any single character encoding per
|
* list, i.e., the server is able to accept any single character encoding per
|
||||||
|
@ -69,7 +69,7 @@ import org.springframework.web.util.UriUtils;
|
||||||
* <td><p>action</p></td>
|
* <td><p>action</p></td>
|
||||||
* <td><p>false</p></td>
|
* <td><p>false</p></td>
|
||||||
* <td><p>true</p></td>
|
* <td><p>true</p></td>
|
||||||
* <td><p><p>HTML Required Attribute</p></td>
|
* <td><p>HTML Required Attribute</p></td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr class="altColor">
|
* <tr class="altColor">
|
||||||
* <td><p>cssClass</p></td>
|
* <td><p>cssClass</p></td>
|
||||||
|
|
|
@ -506,6 +506,109 @@ declare it as an <<mvc-ann-controller-advice>> bean or configure it directly on
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[mvc-exceptionhandlers]]
|
||||||
|
=== Exception Resolution
|
||||||
|
|
||||||
|
If an exception occurs during the mapping or the invocation of a request handler (e.g. an
|
||||||
|
`@Controller`), the `DispatcherServlet` delegates to a chain of `HandlerExceptionResolver`
|
||||||
|
beans to try and resolve the exception and to provide alternative handling for it, which
|
||||||
|
typically means preparing an error response whether an HTML error page, an error status,
|
||||||
|
or both.
|
||||||
|
|
||||||
|
The table below lists the available `HandlerExceptionResolver` implementations:
|
||||||
|
|
||||||
|
[cols="1,2", options="header"]
|
||||||
|
.HandlerExceptionResolver implementations
|
||||||
|
|===
|
||||||
|
| HandlerExceptionResolver| Description
|
||||||
|
|
||||||
|
| `SimpleMappingExceptionResolver`
|
||||||
|
| A mapping between exception class names and error view names. Useful for rendering
|
||||||
|
error pages in a browser application.
|
||||||
|
|
||||||
|
| {api-spring-framework}/web/servlet/mvc/support/DefaultHandlerExceptionResolver.html[DefaultHandlerExceptionResolver]
|
||||||
|
| Resolves exceptions raised by Spring MVC and maps them to HTTP status codes.
|
||||||
|
|
||||||
|
Also see alternative `ResponseEntityExceptionHandler` and <<mvc-ann-rest-exceptions>>.
|
||||||
|
|
||||||
|
| `ResponseStatusExceptionResolver`
|
||||||
|
| Resolves exceptions with the `@ResponseStatus` annotation and maps them to HTTP status
|
||||||
|
codes based on the value in the annotation.
|
||||||
|
|
||||||
|
| `ExceptionHandlerExceptionResolver`
|
||||||
|
| Resolves exceptions by invoking an `@ExceptionHandler` method in an `@Controller` or an
|
||||||
|
`@ControllerAdvice` class. See <<mvc-ann-exceptionhandler>>.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[[mvc-excetionhandlers-handling]]
|
||||||
|
==== Handling
|
||||||
|
|
||||||
|
You chain exception resolvers by declaring more than one exception resolver beans and,
|
||||||
|
if necessary, setting the `order` property to specify ordering. Remember, the higher the
|
||||||
|
order property, the later the exception resolver is positioned in the chain.
|
||||||
|
|
||||||
|
The contract of `HandlerExceptionResolver` specifies that it __can__ return:
|
||||||
|
|
||||||
|
* `ModelAndView` that points to an error view.
|
||||||
|
* Empty `ModelAndView` if the exception was handled within the resolver.
|
||||||
|
* `null` if the exception remains unresolved, for subsequent resolvers to try; if the
|
||||||
|
exception remains unresolved by any resolver, it is re-thrown and left to propagate to
|
||||||
|
the Servlet container.
|
||||||
|
|
||||||
|
To configure exception handling is as simple as adding `HandlerExceptionResolver` beans
|
||||||
|
to your Spring configuration. The <<mvc-config>> automatically declares built-in
|
||||||
|
resolvers for default Spring MVC exceptions, for `@ResponseStatus` annotated exceptions,
|
||||||
|
and for support of `@ExceptionHandler` methods. You can customize that list or replace it.
|
||||||
|
|
||||||
|
|
||||||
|
[[mvc-ann-customer-servlet-container-error-page]]
|
||||||
|
==== Container error page
|
||||||
|
|
||||||
|
If an exception remains unresolved by any `HandlerExceptionResolver` and is therefore
|
||||||
|
left to propagate, or if the response status is set to an error status (i.e. 4xx, 5xx),
|
||||||
|
Servlet containers may render a default error page in HTML. To customize the default
|
||||||
|
error page of the container, you can declare an error page mapping in `web.xml`:
|
||||||
|
|
||||||
|
[source,xml,indent=0]
|
||||||
|
[subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
<error-page>
|
||||||
|
<location>/error</location>
|
||||||
|
</error-page>
|
||||||
|
----
|
||||||
|
|
||||||
|
Given the above, when an exception bubbles up, or the response has an error status, the
|
||||||
|
Servlet container makes an ERROR dispatch within the container to the configured URL
|
||||||
|
(e.g. "/error"). This is then processed by the `DispatcherServlet`, possibly mapping it
|
||||||
|
to an `@Controller` which could be implemented to return an error view name with a model
|
||||||
|
or to render a JSON response as shown below:
|
||||||
|
|
||||||
|
[source,java,indent=0]
|
||||||
|
[subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
@RestController
|
||||||
|
public class ErrorController {
|
||||||
|
|
||||||
|
@RequestMapping(path = "/error")
|
||||||
|
public Map<String, Object> handle(HttpServletRequest request) {
|
||||||
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
map.put("status", request.getAttribute("javax.servlet.error.status_code"));
|
||||||
|
map.put("reason", request.getAttribute("javax.servlet.error.message"));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
The Servlet API does not provide a way to create error page mappings in Java. You can
|
||||||
|
however use both an `WebApplicationInitializer` and a minimal `web.xml`.
|
||||||
|
====
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-viewresolver]]
|
[[mvc-viewresolver]]
|
||||||
=== View Resolution
|
=== View Resolution
|
||||||
[.small]#<<web-reactive.adoc#webflux-viewresolution,Same in Spring WebFlux>>#
|
[.small]#<<web-reactive.adoc#webflux-viewresolution,Same in Spring WebFlux>>#
|
||||||
|
@ -515,7 +618,7 @@ models in a browser without tying you to a specific view technology. `ViewResolv
|
||||||
provides a mapping between view names and actual views. `View` addresses the preparation
|
provides a mapping between view names and actual views. `View` addresses the preparation
|
||||||
of data before handing over to a specific view technology.
|
of data before handing over to a specific view technology.
|
||||||
|
|
||||||
This table below provides more details on the `ViewResolver` hierarchy:
|
The table below provides more details on the `ViewResolver` hierarchy:
|
||||||
|
|
||||||
[[mvc-view-resolvers-tbl]]
|
[[mvc-view-resolvers-tbl]]
|
||||||
.ViewResolver implementations
|
.ViewResolver implementations
|
||||||
|
@ -575,9 +678,9 @@ The contract of a `ViewResolver` specifies that it __can__ return null to indica
|
||||||
view could not be found. However in the case of JSPs, and `InternalResourceViewResolver`,
|
view could not be found. However in the case of JSPs, and `InternalResourceViewResolver`,
|
||||||
the only way to figure out if a JSP exists is to perform a dispatch through
|
the only way to figure out if a JSP exists is to perform a dispatch through
|
||||||
`RequestDispatcher`. Therefore an `InternalResourceViewResolver` must always be configured
|
`RequestDispatcher`. Therefore an `InternalResourceViewResolver` must always be configured
|
||||||
to be last in the overal order of view resolvers.
|
to be last in the overall order of view resolvers.
|
||||||
|
|
||||||
To configure view resolution is as simple as adding a `ViewResolver` beans to your Spring
|
To configure view resolution is as simple as adding `ViewResolver` beans to your Spring
|
||||||
configuration. The <<mvc-config>> provides provides a dedicated configuration API for
|
configuration. The <<mvc-config>> provides provides a dedicated configuration API for
|
||||||
<<mvc-config-view-resolvers>> and also for adding logic-less
|
<<mvc-config-view-resolvers>> and also for adding logic-less
|
||||||
<<mvc-config-view-controller,View Controllers>> which are useful for HTML template
|
<<mvc-config-view-controller,View Controllers>> which are useful for HTML template
|
||||||
|
@ -2666,6 +2769,67 @@ controller-specific ``Formatter``'s:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[mvc-ann-exceptionhandler]]
|
||||||
|
=== Exception Methods
|
||||||
|
|
||||||
|
`@ExceptionHandler` methods in an `@Controller` can be used to handle exceptions during
|
||||||
|
request handling from the same controller. An `@ExceptionHandler` can also be declared
|
||||||
|
in an <<mvc-ann-controller-advice,@ControllerAdvice class>> to apply across controllers.
|
||||||
|
Support for `@ExceptionHandler` methods in Spring MVC is provided through the
|
||||||
|
<<mvc-exceptionhandlers,HandlerExceptionResolver>> mechanism.
|
||||||
|
|
||||||
|
Below is an example:
|
||||||
|
|
||||||
|
[source,java,indent=0]
|
||||||
|
[subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
@Controller
|
||||||
|
public class SimpleController {
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
@ExceptionHandler(IOException.class)
|
||||||
|
public ResponseEntity<String> handle(IOException ex) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
The value of the `@ExceptionHandler` annotation can be set to an array of Exception types
|
||||||
|
to match to. Or if the annotation value is not set, then the exception type declared in
|
||||||
|
the method signature is used instead. `@ExceptionHandler` methods can declare other
|
||||||
|
arguments too, e.g. the `HttpServletRequest`. The return value type can be a `String`,
|
||||||
|
which is interpreted as a view name, a `ModelAndView` object, a `ResponseEntity`, or you
|
||||||
|
can also add the `@ResponseBody` annotation.
|
||||||
|
|
||||||
|
For `@ExceptionHandler` methods, a root exception match will be preferred to just
|
||||||
|
matching a cause of the current exception, among the handler methods of a particular
|
||||||
|
controller or advice bean. However, a cause match on a higher-priority `@ControllerAdvice`
|
||||||
|
will still be preferred to a any match (whether root or cause level) on a lower-priority
|
||||||
|
advice bean. As a consequence, when using a multi-advice arrangement, please declare your
|
||||||
|
primary root exception mappings on a prioritized advice bean with a corresponding order!
|
||||||
|
|
||||||
|
[[mvc-ann-rest-exceptions]]
|
||||||
|
==== REST API exceptions
|
||||||
|
|
||||||
|
A common requirement for REST services is to include error details in the body of the
|
||||||
|
response. The Spring Framework does not automatically do this because the representation
|
||||||
|
of error details in the response body is application specific. However a
|
||||||
|
`@RestController` may use `@ExceptionHandler` methods with a `ResponseEntity` return
|
||||||
|
value to set the status and the body of the response. Such methods may also be declared
|
||||||
|
in `@ControllerAdvice` classes to apply them globally.
|
||||||
|
|
||||||
|
Applications that implement global exception handling with error details in the response
|
||||||
|
body should consider extending
|
||||||
|
{api-spring-framework}/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.html[ResponseEntityExceptionHandler]
|
||||||
|
which provides handling for exceptions that Spring MVC raises along with hooks to
|
||||||
|
customize the response body. To make use of this, create a sub-class of
|
||||||
|
`ResponseEntityExceptionHandler`, annotate with `@ControllerAdvice`, override the
|
||||||
|
necessary methods, and declare it as a Spring bean.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-ann-controller-advice]]
|
[[mvc-ann-controller-advice]]
|
||||||
=== Controller Advice
|
=== Controller Advice
|
||||||
[.small]#<<web-reactive.adoc#webflux-ann-controller-advice,Same in Spring WebFlux>>#
|
[.small]#<<web-reactive.adoc#webflux-ann-controller-advice,Same in Spring WebFlux>>#
|
||||||
|
@ -2929,265 +3093,6 @@ in order to use a specific instance of `MvcUriComponentsBuilder` with a custom b
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-exceptionhandlers]]
|
|
||||||
== Exception Handling
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-exceptionhandlers-overview]]
|
|
||||||
=== Overview
|
|
||||||
|
|
||||||
Spring `HandlerExceptionResolver` implementations deal with unexpected exceptions that
|
|
||||||
occur during controller execution. A `HandlerExceptionResolver` somewhat resembles the
|
|
||||||
exception mappings you can define in the web application descriptor `web.xml`. However,
|
|
||||||
they provide a more flexible way to do so. For example they provide information about
|
|
||||||
which handler was executing when the exception was thrown. Furthermore, a programmatic
|
|
||||||
way of handling exceptions gives you more options for responding appropriately before
|
|
||||||
the request is forwarded to another URL (the same end result as when you use the Servlet
|
|
||||||
specific exception mappings).
|
|
||||||
|
|
||||||
Besides implementing the `HandlerExceptionResolver` interface, which is only a matter of
|
|
||||||
implementing the `resolveException(Exception, Handler)` method and returning a
|
|
||||||
`ModelAndView`, you may also use the provided `SimpleMappingExceptionResolver` or create
|
|
||||||
`@ExceptionHandler` methods. The `SimpleMappingExceptionResolver` enables you to take
|
|
||||||
the class name of any exception that might be thrown and map it to a view name. This is
|
|
||||||
functionally equivalent to the exception mapping feature from the Servlet API, but it is
|
|
||||||
also possible to implement more finely grained mappings of exceptions from different
|
|
||||||
handlers. The `@ExceptionHandler` annotation on the other hand can be used on methods
|
|
||||||
that should be invoked to handle an exception. Such methods may be defined locally
|
|
||||||
within an `@Controller` or may apply to many `@Controller` classes when defined within an
|
|
||||||
`@ControllerAdvice` class. The following sections explain this in more detail.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-ann-exceptionhandler]]
|
|
||||||
=== @ExceptionHandler
|
|
||||||
|
|
||||||
The `HandlerExceptionResolver` interface and the `SimpleMappingExceptionResolver`
|
|
||||||
implementations allow you to map Exceptions to specific views declaratively along with
|
|
||||||
some optional Java logic before forwarding to those views. However, in some cases,
|
|
||||||
especially when relying on `@ResponseBody` methods rather than on view resolution, it
|
|
||||||
may be more convenient to directly set the status of the response and optionally write
|
|
||||||
error content to the body of the response.
|
|
||||||
|
|
||||||
You can do that with `@ExceptionHandler` methods. When declared within a controller such
|
|
||||||
methods apply to exceptions raised by `@RequestMapping` methods of that controller (or
|
|
||||||
any of its subclasses). You can also declare an `@ExceptionHandler` method within an
|
|
||||||
`@ControllerAdvice` class in which case it handles exceptions from `@RequestMapping`
|
|
||||||
methods from many controllers. Below is an example of a controller-local
|
|
||||||
`@ExceptionHandler` method:
|
|
||||||
|
|
||||||
[source,java,indent=0]
|
|
||||||
[subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
@Controller
|
|
||||||
public class SimpleController {
|
|
||||||
|
|
||||||
// @RequestMapping methods omitted ...
|
|
||||||
|
|
||||||
@ExceptionHandler(IOException.class)
|
|
||||||
public ResponseEntity<String> handleIOException(IOException ex) {
|
|
||||||
// prepare responseEntity
|
|
||||||
return responseEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
The `@ExceptionHandler` value can be set to an array of Exception types. If an exception
|
|
||||||
is thrown that matches one of the types in the list, then the method annotated with the
|
|
||||||
matching `@ExceptionHandler` will be invoked. If the annotation value is not set then
|
|
||||||
the exception types listed as method arguments are used.
|
|
||||||
|
|
||||||
[TIP]
|
|
||||||
====
|
|
||||||
For `@ExceptionHandler` methods, a root exception match will be preferred to just
|
|
||||||
matching a cause of the current exception, among the handler methods of a particular
|
|
||||||
controller or advice bean. However, a cause match on a higher-priority `@ControllerAdvice`
|
|
||||||
will still be preferred to a any match (whether root or cause level) on a lower-priority
|
|
||||||
advice bean. As a consequence, when using a multi-advice arrangement, please declare your
|
|
||||||
primary root exception mappings on a prioritized advice bean with a corresponding order!
|
|
||||||
====
|
|
||||||
|
|
||||||
Much like standard controller methods annotated with a `@RequestMapping` annotation, the
|
|
||||||
method arguments and return values of `@ExceptionHandler` methods can be flexible. For
|
|
||||||
example, the `HttpServletRequest` can be accessed in Servlet environments. The return
|
|
||||||
type can be a `String`, which is interpreted as a view name, a `ModelAndView` object,
|
|
||||||
a `ResponseEntity`, or you can also add the `@ResponseBody` to have the method return
|
|
||||||
value converted with message converters and written to the response stream.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-ann-rest-spring-mvc-exceptions]]
|
|
||||||
=== Framework exceptions
|
|
||||||
|
|
||||||
Spring MVC may raise a number of exceptions while processing a request. The
|
|
||||||
`SimpleMappingExceptionResolver` can easily map any exception to a default error view as
|
|
||||||
needed. However, when working with clients that interpret responses in an automated way
|
|
||||||
you will want to set specific status code on the response. Depending on the exception
|
|
||||||
raised the status code may indicate a client error (4xx) or a server error (5xx).
|
|
||||||
|
|
||||||
The `DefaultHandlerExceptionResolver` translates Spring MVC exceptions to specific error
|
|
||||||
status codes. It is registered by default with the MVC namespace, the MVC Java config,
|
|
||||||
and also by the `DispatcherServlet` (i.e. when not using the MVC namespace or Java
|
|
||||||
config). Listed below are some of the exceptions handled by this resolver and the
|
|
||||||
corresponding status codes:
|
|
||||||
|
|
||||||
|===
|
|
||||||
| Exception| HTTP Status Code
|
|
||||||
|
|
||||||
| `BindException`
|
|
||||||
| 400 (Bad Request)
|
|
||||||
|
|
||||||
| `ConversionNotSupportedException`
|
|
||||||
| 500 (Internal Server Error)
|
|
||||||
|
|
||||||
| `HttpMediaTypeNotAcceptableException`
|
|
||||||
| 406 (Not Acceptable)
|
|
||||||
|
|
||||||
| `HttpMediaTypeNotSupportedException`
|
|
||||||
| 415 (Unsupported Media Type)
|
|
||||||
|
|
||||||
| `HttpMessageNotReadableException`
|
|
||||||
| 400 (Bad Request)
|
|
||||||
|
|
||||||
| `HttpMessageNotWritableException`
|
|
||||||
| 500 (Internal Server Error)
|
|
||||||
|
|
||||||
| `HttpRequestMethodNotSupportedException`
|
|
||||||
| 405 (Method Not Allowed)
|
|
||||||
|
|
||||||
| `MethodArgumentNotValidException`
|
|
||||||
| 400 (Bad Request)
|
|
||||||
|
|
||||||
| `MissingPathVariableException`
|
|
||||||
| 500 (Internal Server Error)
|
|
||||||
|
|
||||||
| `MissingServletRequestParameterException`
|
|
||||||
| 400 (Bad Request)
|
|
||||||
|
|
||||||
| `MissingServletRequestPartException`
|
|
||||||
| 400 (Bad Request)
|
|
||||||
|
|
||||||
| `NoHandlerFoundException`
|
|
||||||
| 404 (Not Found)
|
|
||||||
|
|
||||||
| `NoSuchRequestHandlingMethodException`
|
|
||||||
| 404 (Not Found)
|
|
||||||
|
|
||||||
| `TypeMismatchException`
|
|
||||||
| 400 (Bad Request)
|
|
||||||
|===
|
|
||||||
|
|
||||||
The `DefaultHandlerExceptionResolver` works transparently by setting the status of the
|
|
||||||
response. However, it stops short of writing any error content to the body of the
|
|
||||||
response while your application may need to add developer-friendly content to every
|
|
||||||
error response for example when providing a REST API. You can prepare a `ModelAndView`
|
|
||||||
and render error content through view resolution -- i.e. by configuring a
|
|
||||||
`ContentNegotiatingViewResolver`, `MappingJackson2JsonView`, and so on. However, you may
|
|
||||||
prefer to use `@ExceptionHandler` methods instead.
|
|
||||||
|
|
||||||
If you prefer to write error content via `@ExceptionHandler` methods you can extend
|
|
||||||
`ResponseEntityExceptionHandler` instead. This is a convenient base for
|
|
||||||
`@ControllerAdvice` classes providing an `@ExceptionHandler` method to handle standard
|
|
||||||
Spring MVC exceptions and return `ResponseEntity`. That allows you to customize the
|
|
||||||
response and write error content with message converters. See the
|
|
||||||
`ResponseEntityExceptionHandler` javadocs for more details.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-ann-rest-exceptions]]
|
|
||||||
=== REST API exceptions
|
|
||||||
|
|
||||||
An `@RestController` may use `@ExceptionHandler` methods that return a
|
|
||||||
`ResponseEntity` to provide both a response status and error details in the body
|
|
||||||
of the response. Such methods may also be added to `@ControllerAdvice`
|
|
||||||
classes for exception handling across a subset or all controllers.
|
|
||||||
|
|
||||||
A common requirement is to include error details in the body of the response.
|
|
||||||
Spring does not automatically do this (although Spring Boot does) because the
|
|
||||||
representation of error details in the response body is application specific.
|
|
||||||
|
|
||||||
Applications that wish to implement a global exception handling strategy with
|
|
||||||
error details in the response body should consider extending the abstract base
|
|
||||||
class `ResponseEntityExceptionHandler` which provides handling for the exceptions
|
|
||||||
that Spring MVC raises and provides hooks to customize the response body as
|
|
||||||
well as to handle other exceptions. Simply declare the extension class as a
|
|
||||||
Spring bean and annotate it with `@ControllerAdvice`. For more details see
|
|
||||||
See `ResponseEntityExceptionHandler`.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-ann-annotated-exceptions]]
|
|
||||||
=== Annotated Exception
|
|
||||||
|
|
||||||
A business exception can be annotated with `@ResponseStatus`. When the exception is
|
|
||||||
raised, the `ResponseStatusExceptionResolver` handles it by setting the status of the
|
|
||||||
response accordingly. By default the `DispatcherServlet` registers the
|
|
||||||
`ResponseStatusExceptionResolver` and it is available for use.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-ann-customer-servlet-container-error-page]]
|
|
||||||
=== Container error page
|
|
||||||
|
|
||||||
When the status of the response is set to an error status code and the body of the
|
|
||||||
response is empty, Servlet containers commonly render an HTML formatted error page. To
|
|
||||||
customize the default error page of the container, you can declare an `<error-page>`
|
|
||||||
element in `web.xml`. Up until Servlet 3, that element had to be mapped to a specific
|
|
||||||
status code or exception type. Starting with Servlet 3 an error page does not need to be
|
|
||||||
mapped, which effectively means the specified location customizes the default Servlet
|
|
||||||
container error page.
|
|
||||||
|
|
||||||
[source,xml,indent=0]
|
|
||||||
[subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
<error-page>
|
|
||||||
<location>/error</location>
|
|
||||||
</error-page>
|
|
||||||
----
|
|
||||||
|
|
||||||
Note that the actual location for the error page can be a JSP page or some other URL
|
|
||||||
within the container including one handled through an `@Controller` method:
|
|
||||||
|
|
||||||
When writing error information, the status code and the error message set on the
|
|
||||||
`HttpServletResponse` can be accessed through request attributes in a controller:
|
|
||||||
|
|
||||||
[source,java,indent=0]
|
|
||||||
[subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
@Controller
|
|
||||||
public class ErrorController {
|
|
||||||
|
|
||||||
@RequestMapping(path = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
|
||||||
@ResponseBody
|
|
||||||
public Map<String, Object> handle(HttpServletRequest request) {
|
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
|
||||||
map.put("status", request.getAttribute("javax.servlet.error.status_code"));
|
|
||||||
map.put("reason", request.getAttribute("javax.servlet.error.message"));
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
or in a JSP:
|
|
||||||
|
|
||||||
[source,xml,indent=0]
|
|
||||||
[subs="verbatim,quotes"]
|
|
||||||
----
|
|
||||||
<%@ page contentType="application/json" pageEncoding="UTF-8"%>
|
|
||||||
{
|
|
||||||
status:<%=request.getAttribute("javax.servlet.error.status_code") %>,
|
|
||||||
reason:<%=request.getAttribute("javax.servlet.error.message") %>
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[mvc-ann-async]]
|
[[mvc-ann-async]]
|
||||||
== Async Requests
|
== Async Requests
|
||||||
[.small]#<<mvc-ann-async-vs-webflux,Compared to WebFlux>>#
|
[.small]#<<mvc-ann-async-vs-webflux,Compared to WebFlux>>#
|
||||||
|
|
Loading…
Reference in New Issue