Handler methods with the @RequestMapping
annotation have a flexible signature and can choose from a
range of supported controller method arguments and return values.
Method arguments
The following table describes supported controller method arguments. Reactive types are not supported for any arguments.
The java.util.Optional
argument from JDK 8 is supported as a method argument in combination with
annotations that have the required
attribute (for example, @RequestParam
, @RequestHeader
and others), and is equivalent to required=false
.
Controller method argument | Description |
---|---|
|
Provides typed access to request parameters and request and session attributes, without directly using the Servlet API. |
|
Intended to select any specific type of request or response - for example, |
|
Ensures that a session exists. As a consequence, such an argument is never |
|
Servlet 4.0 build pusher API for programmatic push ) HTTP/2 resources. Note that, according to the
Servlet specification, the injected |
|
The current authenticated user - possibly a concrete implementation class of Note that this argument is not accelerated recognized if it has an annotation designed to allow a custom
resolver to recognize it before falling back to default recognition via |
|
HTTP request method. |
|
The current locale of the request, determined by the most specific |
|
The time zone associated with the current request, as determined by the
|
|
Designed to provide access to the raw request body as it is presented in the Servlet API. |
|
Designed to provide access to the raw response body exposed by the Servlet API. |
|
Designed to provide access to URI pattern variables. |
|
Designed to provide access to pairs "name-value" in URI path segments. |
|
Designed to provide access to servlet request parameters, including multipart files. Parameter values are converted to the declared type of the method arguments. Note that the use of the |
|
Designed to provide access to request headers. Header values are converted to the declared type of the method argument. |
|
Designed to provide access to cookies . Cookie values are converted to the declared method argument type. |
|
To access the HTTP request body. The body content is converted to the declared method argument type using
|
|
Designed to provide access to request headers and body. The body is converted using |
|
Designed to provide access to a component in a |
|
Designed to provide access to a model that is used in HTML controllers and exposed in templates as part of the view rendering. |
|
Specifies the attributes that will be used in the event of a redirect (that is, will be added to request line), flash attributes that will be temporarily stored until the request arrives after a redirect. |
|
To access an existing attribute in the model (of which an instance is created if it is missing) with data binding and validation. Note that use the |
|
Designed to provide access to validation and data binding errors for a command object (that is, an
argument with the |
|
Intended to mark completion of form processing, which causes session attributes declared through the
|
|
Designed to prepare a URL associated with the host, port, scheme, context path of the current request, and servlet mapping literal component. |
|
Designed to provide access to any session attribute, as opposed to model attributes, stored in the
session as a result of declaring the |
|
Designed to provide access to request attributes. |
Any other argument |
If argument method does not match any of the previous values in this table and is a simple type (as
defined by BeanUtils#isSimpleProperty), it resolves to |
Return values
In the following The table describes the supported return values of the controller method. Reactive types are supported for all return values.
Return value of the controller method | Description |
---|---|
|
The return value is converted through the |
|
Return value specifying the full response (including HTTP headers and body), converted through the |
|
Designed to return a response with headers and no body. |
|
The name of the view to be recognized by |
|
A |
|
Attributes added to the implicit model, with the view name implicitly defined via |
|
Attribute , added to the model whose view name is implicitly specified via Note that the |
|
The view and model attributes to use and, if necessary, the response status. |
|
A method with a return type If neither of the above is true, the return type is |
|
Produces any of the previous return values asynchronously from any thread - for example, as a result of an event or callback. |
|
Produces any of the above returned values asynchronously in a thread managed by Spring MVC. |
|
A more convenient alternative to |
|
Asynchronously spawns a stream of objects to write to the response using
|
|
Asynchronous writing to |
Reactive types - Reactor, RxJava, or others via |
Alternative to In streaming scenarios (for example, |
Any other return value |
Any return value that does not match any of previous values in this table and is a |
Type conversion
Some annotated controller method arguments representing request input based on
String
(such as @RequestParam
, @RequestHeader
, @PathVariable
,
@MatrixVariable
and @CookieValue
) may require a type conversion if the argument is not
declared as a String
.
In such cases, the type conversion is applied automatically based on the
configured converters. By default, simple types are supported (int
, long
,
Date
and others). You can configure type conversion via WebDataBinder
or by registering
Formatters
with the FormattingConversionService
.
A practical issue with type
conversion is handling empty the original value of the string. Such a value is considered missing if it becomes
null
as a result of a type conversion. This may be true for Long
, UUID
and
other target types. If you need to allow null
injection, then either use the required
flag
in the argument annotation, or declare the argument as @Nullable
.
Starting in version 5.3, non-null arguments will be honored even after
type conversion. If the handler method is expected to accept a null value, then either declare the argument as
@Nullable
, or mark it as required=false
in the appropriate @RequestParam
etc.
This is the best practice and recommended solution for regressions encountered when upgrading to
version 5.3.
In addition, you can specially handle, for example, the MissingPathVariableException
exception that
is raised if the annotation @PathVariable
is required. A Null value after conversion will be
treated as an empty original value, so the corresponding Missing...Exception
exception will be
generated.
Matrix Variables
In RFC 3986 describes name-value pairs in path segments. In Spring MVC we call them "matrix variables", based on "old post" by Tim Berners-Lee, but can also be called URI path parameters.
Matrix variables can appear in any path segment, with each
variable separated by a semicolon and multiple values separated by a comma (for example,
/cars;color=red,green;year=2012
). Multiple values can also be specified through repeated variable names
(for example, color=red;color=green;color=blue
).
If the URL is expected to contain matrix variables, then the request mapping for a controller method must use a URI variable to mask the contents of such a matrix variable and ensure successful request mapping regardless of the order or presence of the matrix variables. The following example uses a matrix variable:
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
fun findPet(@PathVariable petId: String, @MatrixVariable q: Int) {
// petId == 42
// q == 11
}
Given that all path segments can contain matrix variables, sometimes it can you will need to determine which path variable the matrix variable should be in. The following example shows how to do this:
// GET /owners/42;q=11/pets/21;q=22
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable(name="q", pathVar="ownerId") int q1,
@MatrixVariable(name="q", pathVar="petId") int q2) {
// q1 == 11
// q2 == 22
}
// GET /owners/42;q=11/pets/21;q=22
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
@MatrixVariable(name = "q", pathVar = "ownerId") q1: Int,
@MatrixVariable(name = "q", pathVar = "petId") q2: Int) {
// q1 == 11
// q2 == 22
}
A matrix variable can be defined as optional and have a default value, as shown in the following example:
// GET /pets/42
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
// q == 1
}
// GET /pets/42
@GetMapping("/pets/{petId}")
fun findPet(@MatrixVariable(required = false, defaultValue = "1") q: Int) {
// q == 1
}
To get all matrix variables, you can use MultiValueMap
as shown in the following example:
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable MultiValueMap<String, String> matrixVars,
@MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) {
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
@MatrixVariable matrixVars: MultiValueMap<String, String>,
@MatrixVariable(pathVar="petId") petMatrixVars: MultiValueMap<String, String>) {
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}
Please note that the use of matrix variables must be enabled. In MVC configuration in Java, you need to set
UrlPathHelper
when removeSemicolonContent=false
via Path Matching. In the MVC namespace on
XML you can set <mvc:annotation-driven enable-matrix-variables="true"/>
.
@RequestParam
The @RequestParam
annotation can be used to bind servlet request parameters (that is, request
parameters or form data) to a method argument in the controller.
In the following example shows how to do this:
@Controller
@RequestMapping("/pets")
public class EditPetForm {
// ...
@GetMapping
public String setupForm( @RequestParam("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
// ...
}
- Using the
@RequestParam
annotation for bindingspetId
.
import org.springframework.ui.set
@Controller
@RequestMapping("/pets" )
class EditPetForm {
// ...
@GetMapping
fun setupForm(@RequestParam("petId") petId: Int, model: Model): String {
val pet = this.clinic.loadPet(petId);
model["pet"] = pet
return "petForm"
}
// ...
}
- Using the
@RequestParam
annotation to bind thepetId
.
By default, method parameters that use this annotation are required, but you can specify that the method
parameter is optional by setting the required
flag of the @RequestParam
annotation to
false
or by declaring the argument using the java.util.Optional
wrapper function.
Type conversion is applied automatically if the target method's parameter type is not String
.
Declaring the argument type as an array or list allows multiple parameter values for the same parameter name.
If the @RequestParam
annotation is declared as Map<String, String>
or MultiValueMap<String
, String>
without specifying a parameter name in the annotation, then the Map is populated with the
request parameter values for each given parameter name.
Note that using the @RequestParam
annotation is optional (for example, to set attributes). By default, any argument that is a simple value type (as
defined by BeanUtils#isSimpleProperty) and is not resolved by any other argument resolver, is
treated as if it were annotated with @RequestParam
.
@RequestHeader
You
can use the @RequestHeader
annotation to bind the request header to a method argument in the
controller.
Consider the following request with headers:
Host localhost:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9 Accept-Language fr,en-gb;q=0.7,en;q=0.3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive 300
The following example shows how to get the value of the Accept-Encoding
headers and
Keep-Alive
:
@GetMapping("/demo")
public void handle(
@RequestHeader(" Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
- We get the values of the
Accept-Encoding
header. - We get the values of the
Keep-Alive
header.
@GetMapping("/demo")
fun handle(
@RequestHeader("Accept-Encoding") encoding: String,
@RequestHeader("Keep-Alive") keepAlive: Long) {
//...
}
- Get the values of the
Accept-Encoding
header. - Get the values of the header
Keep-Alive
.
If the target method parameter type is not String
, type conversion is applied automatically.
If the @RequestHeader
annotation is used in a Map<String, String>
, MultiValueMap<String,
String>
, or HttpHeaders
argument , The Map is populated with all header values.
@RequestHeader("Accept")
can be of type String
, as well as
String[]
or List<String>
.
@CookieValue
The @CookieValue
annotation can be used to bind HTTP data type
values cookie to a method argument in the controller.
Consider a request with the following cookie:
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
The following example shows how to get the cookie value:
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//. ..
}
- Getting the
JSESSIONID
cookie value.
@GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) {
//...
}
- Get the value of the
JSESSIONID
cookie.
If the target method parameter type is not String
, type conversion is applied automatically.
@ModelAttribute
The @ModelAttribute
annotation can be used on a method argument to
access the attribute from the model or create an instance of it if it is missing. The model attribute is also
overlaid with values from the servlet request parameters via HTTP, the names of which coincide with the names of the
fields. This is called data binding, and it eliminates the need to parse and transform individual query parameters
and form fields. The following example shows how to do this:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// method logic...
}
@PostMapping( "/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String {
// method logic...
}
The above Pet
instance is obtained in one of the following ways:
Retrieved from the model where it may have been added by a method with the @ModelAttribute annotation.
Retrieved from the HTTP session if the model attribute was specified in the
@SessionAttributes
annotation at the class level.Received through some kind of
Converter
, where the name of the model attribute is the same as the name of the request value, for example, a path variable or request parameter (see. following example).Created using the default constructor.
Created via the "primary constructor" with arguments corresponding to the parameters servlet request. Argument names are specified through the
@ConstructorProperties
annotation of JavaBeans classes or through run-time bytecode-stored parameter names.
An alternative to using a method with the @ModelAttribute annotation to provide it, or to call the framework to
create a model attribute, is to use Converter<String, T>
to provide an instance. This is
applicable if the model attribute name is the same as the name of a query value, such as a path variable or
query parameter, and there is a Converter
from String
to the model attribute type. In
the following example, the model attribute name is account
, which corresponds to the URI path
variable account
, and there is also a registered Converter<String, Account>
.
which can load Account
from the data store:
@PutMapping("/accounts/{account}")
public String save( @ModelAttribute("account") Account account) {
// ...
}
@PutMapping ("/accounts/{account}")
fun save(@ModelAttribute("account") account: Account): String {
// ...
}
After receiving the model attribute instance, data binding is applied. The WebDataBinder
class maps
servlet request parameter names (query parameters and form fields) to target object field names. Matched fields are
populated after applying type conversion where necessary.
Data binding can cause errors. By default, a BindException
exception is thrown. However, to check for such errors in a controller method, you can add a
BindingResult
argument directly next to the @ModelAttribute
annotation, as shown in the
following example:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
- Adding
BindingResult
next to the annotation@ModelAttribute
.
@PostMapping("/owners/{ownerId}/pets/{petId}/ edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String {
if (result.hasErrors ()) {
return "petForm"
}
// ...
}
- Adding
BindingResult
next to the@ModelAttribute
annotation.
In some cases, you may need to access a model attribute without data binding. For such cases, you can inject a
Model
into the controller and access it directly, or alternatively set @ModelAttribute(binding=false)
,
as shown in the following example:
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
return accountRepository.findOne(accountId);
}
@PostMapping("update")
public String update(@Valid AccountForm form, BindingResult result,
@ModelAttribute(binding=false) Account account) {
// ...
}
- Setting
@ModelAttribute(binding=false)
.
@ModelAttribute
fun setUpForm(): AccountForm {
return AccountForm()
}
@ModelAttribute
fun findAccount(@PathVariable accountId : String): Account {
return accountRepository.findOne(accountId)
}
@PostMapping("update")
fun update(@Valid form: AccountForm, result: BindingResult,
@ModelAttribute(binding = false) account: Account): String {
// ...
}
- Setting
@ModelAttribute(binding=false)
.
You can automatically apply validation after data binding by adding the javax.validation.Valid
annotation
or the @Validated
annotation from Spring. The following example shows how to do this:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
- Validate the
Pet
instance.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute( "pet") pet: Pet, result: BindingResult): String {
if (result.hasErrors()) {
return "petForm"
}
// ...
}
Note that using the @ModelAttribute
annotation is optional (for example, to set attributes). By
default, any argument that is not a simple value type (as defined by BeanUtils#isSimpleProperty) and is not resolved by any other argument resolver, is
treated as if it were annotated with @ModelAttribute
.
@SessionAttributes
The @SessionAttributes
annotation is used to store model attributes in a servlet HTTP session between
requests. This is a type-level annotation that declares the session attributes used by a particular controller. This
typically lists the model attribute names or model attribute types that should be transparently stored in the
session for subsequent access requests.
The following example uses the @SessionAttributes
annotation:
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
}
- Using the
@SessionAttributes
annotation.
@Controller
@SessionAttributes("pet")
class EditPetForm {
// ...
}
- Using the
@SessionAttributes
annotation.
On the first request, when a model attribute named pet
is added to the model, it is automatically
promoted and stored in the servlet's HTTP session. It remains there until another controller method uses the SessionStatus
method argument to clear the storage, as shown in the following example:
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
@PostMapping("/pets/{id }")
public String handle(Pet pet, BindingResult errors, SessionStatus status) {
if (errors.hasErrors) {
// ...
}
status.setComplete();
// ...
}
}
- Storing the
Pet
value in the servlet session. - Clearing the
Pet
value from the servlet session.
@Controller
@SessionAttributes("pet")
class EditPetForm {
// ...
@PostMapping("/pets/{id}")
fun handle(pet: Pet, errors: BindingResult, status: SessionStatus): String {
if (errors.hasErrors()) {
// ...
}
status.setComplete()
// ...
}
}
- Storing the
Pet
value in the servlet session. - Clearing the
Pet
value from the servlet session.
@SessionAttribute
If you need access to pre-existing session attributes that are managed globally (that is, outside the controller
- for example, by a filter) and can present or absent, you can use the @SessionAttribute
annotation
on the method parameter, as shown in the following example:
@RequestMapping("/")
public String handle(@SessionAttribute User user) {
// ...
}
- Using the
@SessionAttribute
annotation.
@RequestMapping("/")
fun handle(@SessionAttribute user: User): String {
// ..
}
For use cases that require adding or removing session attributes, consider implementing org.springframework.web.context.request.WebRequest
or javax.servlet.http.HttpSession
into a controller method.
To temporarily store model attributes in a session as part of the controller workflow, consider using the @SessionAttributes
annotation.
@RequestAttribute
Similar to the @SessionAttribute
annotation, you can use the @RequestAttribute
to provide
access to existing request attributes created earlier (for example, Filter
or
HandlerInterceptor
servlets):
@GetMapping("/")
public String handle(@RequestAttribute Client client) {
// ...
}
- Using the
@RequestAttribute
annotation.
@GetMapping("/")
fun handle(@RequestAttribute client: Client): String {
// ...
}
- Using the
@ annotation RequestAttribute
.
Redirect Attributes
By default, all model attributes are considered to be in the form of a URI pattern in the redirect URL. Of the remaining attributes, those that are primitive types or collections or arrays of primitive types are automatically added as query parameters.
Adding primitive type attributes as query parameters may be the desired result if the model instance was prepared
specifically for redirection However, in annotated controllers, the model may contain additional attributes
added for visualization purposes (for example, dropdown field values). To avoid such attributes appearing in the
URL, a method marked with the @RequestMapping
annotation can declare an argument of type RedirectAttributes
and use it to specify the exact attributes that should be available RedirectView
. If the method
performs a redirect, the contents of RedirectAttributes
are used. Otherwise, the contents of the
model are used.
RequestMappingHandlerAdapter
provides a ignoreDefaultModelOnRedirect
flag that can be
used to indicate that the contents of the default Model
should never be used in a redirect
controller method. Instead, the controller method must declare an attribute of type
RedirectAttributes
, or, if it does not, then no attributes should be passed to
RedirectView
. In both the MVC namespace and the Java MVC configuration, this flag is set to
false
to maintain backward compatibility. However, for new applications, we recommend setting this to
true
.
Note that the URI template variables from this request are automatically made available when the redirect URL is
expanded, so add them explicitly via Model
or RedirectAttributes
is not required. The
following example shows how to define a redirect:
@PostMapping("/files/{path}")
public String upload(...) {
// ...
return "redirect:files/{path}";
}
@PostMapping("/files/{path}")
fun upload(... ): String {
// ...
return "redirect:files/{path}"
}
Another way to pass data to the redirect target is to use flash attributes . Unlike other redirect attributes, flash attributes are temporarily stored in the HTTP session (and therefore are not displayed in the URL).
Flash attributes
Flash attributes provide the ability to store attributes one request, intended for use in another request. Most often this is needed when redirecting - for example, the Post-Redirect-Get pattern. Flash attributes are temporarily stored before a redirect (usually in a session) so that they are available for request after the redirect, and are then immediately removed.
Spring MVC has two main abstractions for supporting flash attributes. FlashMap
is used to store
flash attributes, and FlashMapManager
is used to store, retrieve, and manage instances of FlashMap
.
Support for flash attributes is always "on" and does not require explicit activation. However, if it is not used,
it will never create an HTTP session. With each request, there is an "input" FlashMap
with the
attributes passed in from the previous request (if any), and an "output" FlashMap
with the
attributes that need to be saved for the subsequent request. Both FlashMap
instances are accessible
from anywhere in Spring MVC via static methods in RequestContextUtils
.
Annotated controllers generally do not need to work directly with FlashMap
. Instead, a method
annotated with @RequestMapping
can take an argument of type RedirectAttributes
and use
it to add flash attributes for the redirection script. Flash attributes added via
RedirectAttributes
are automatically propagated to the "output" FlashMap. Likewise, after a
redirect, attributes from the "input" FlashMap
are automatically added to the Model
of
the controller serving the target URL.
Multipart
After activating the MultipartResolver
the contents of POST requests with
multipart/form-data
is parsed and becomes available as normal request parameters. The following
example accesses one regular form field and one uploaded file:
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(@RequestParam("name") name: String,
@RequestParam("file") file: MultipartFile): String {
if (!file.isEmpty) {
val bytes = file.bytes
// store the bytes somewhere
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
Declaring the argument type as List<MultipartFile>
allows you to allow multiple files for one
and same parameter name.
If the @RequestParam
annotation is declared as Map<String, MultipartFile>
or
MultiValueMap<String, MultipartFile>
without a parameter name specified in the annotation,
then the Map is filled with multi-part files for each given parameter name.
javax.servlet.http.Part
instead of MultipartFile
from Spring as a method argument or collection value type.
You can also use multipart content as a data binding element to the command object. For example, the form field and file from the previous example could be form object fields, as shown in the following example:
class MyForm {
private String name;
private MultipartFile file;
// ...
}
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(MyForm form, BindingResult errors) {
if (!form.getFile().isEmpty()) {
byte[] bytes = form.getFile().getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
class MyForm(val name: String, val file: MultipartFile, ...)
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(form: MyForm, errors: BindingResult): String {
if (!form.file.isEmpty) {
val bytes = form.file.bytes
// store the bytes somewhere
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
Multi-part requests can also be sent from non-browser clients in a RESTful service scenario. The following example shows a JSON file:
POST /someUrl Content-Type: multipart/mixed --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp Content-Disposition: form-data; name="meta-data" Content-Type: application/json; charset=UTF-8 Content-Transfer-Encoding: 8bit { "name": "value" } --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp Content-Disposition: form-data; name="file-data"; filename="file.properties" Content-Type: text/xml Content-Transfer-Encoding: 8bit ... File Data ...
You can access the " metadata" with the @RequestParam
annotation as a String
, but
you'll probably want it to be deserialized from JSON (similar to the @RequestBody
annotation
code>). Use the @RequestPart
annotation to access a multi-part file after it has been converted
using HttpMessageConverter:
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@RequestPart("file-data") MultipartFile file) {
// ...
}
@PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData,
@RequestPart("file-data") file: MultipartFile): String {
// ...
}
You can use the @RequestPart
annotation in combination with javax.validation.Valid
or
use the @Validated
annotation from Spring, which causes the standard Bean Validation to be applied.
By default, validation errors result in a MethodArgumentNotValidException
exception, which turns
into a 400 (BAD_REQUEST) response. Alternatively, you can handle validation errors locally in the controller via
the Errors
or BindingResult
argument, as shown in the following example:
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
BindingResult result) {
// ...
}
@PostMapping("/")
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData,
result: BindingResult): String {
// ...
}
@RequestBody
Annotation @RequestBody
can be used so that the body of the request can be read and deserialized
into a Object
via the HttpMessageConverter
. The following example uses an argument
with the @RequestBody
annotation:
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
// ...
}
The Message Converters option in the MVC configuration can be used to configure or configure message conversion.
You can use the @RequestBody
annotation in combination with javax.validation.Valid
or
the @Validated
annotation from Spring, which trigger the application standard Bean Validation. By
default, validation errors result in a MethodArgumentNotValidException
exception, which turns into
a 400 (BAD_REQUEST) response. Alternatively, you can handle validation errors locally in the controller via the
Errors
or BindingResult
argument, as shown in the following example:
@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
// ...
}
@PostMapping("/accounts")
fun handle(@Valid @RequestBody account: Account, result: BindingResult) {
// ...
}
HttpEntity
The HttpEntity
class is more or less identical in terms of using the @RequestBody
annotation, but is based on a container object that exposes the request headers and body. The following listing
is an example:
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
@PostMapping("/accounts")
fun handle(entity: HttpEntity<Account>) {
// ...
}
@ResponseBody
Annotation @ResponseBody
can be used for a method to have the return serialized into the response
body via HttpMessageConverter. The following listing is an example:
@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
// ...
}
@GetMapping("/accounts/{id}")
@ResponseBody
fun handle(): Account {
// ...
}
@ResponseBody
is also supported at the class level, in which case it is inherited by all methods
controller. This is the effect of the @RestController
annotation, which is nothing more than a
meta annotation marked with the @Controller
and @ResponseBody annotations.
You can use @ResponseBody
with reactive types.
You can use the Message Converters option in the MVC configuration to configure or customize message conversion.
You can combine methods marked with the @ResponseBody
annotation, with serialization
representations in JSON format.
ResponseEntity
The ResponseEntity
class is similar to the @ResponseBody
annotation, but with
status and headings. For example:
@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).body(body);
}
@GetMapping("/something")
fun handle(): ResponseEntity<String> {
val body = ...
val etag = ...
return ResponseEntity.ok().eTag(etag).build(body)
}
Spring MVC supports the use of a single-value reactive type to asynchronously create a
ResponseEntity
, and/or single- and multi-value reactive types for the body. This allows the
following types of asynchronous responses:
ResponseEntity<Mono<T>>
orResponseEntity<Flux<T>>
report the response status and headers immediately, while the response body is provided asynchronously at a later point. UseMono
if the body consists of 0..1 values, orFlux
if it can create multiple values.Mono<ResponseEntity<T>>
provides all three parameters - response status, headers and body - asynchronously at a later point. This allows you to change the response status and headers depending on the results of asynchronous request processing.
Jackson JSON
Spring provides support for the Jackson JSON library.
JSON Views
Spring MVC provides native support for view serialization Jackson's Serialization
Views, which allows you to display only a subset of all fields of an object. To use it with controller
methods annotated with @ResponseBody
, or with the ResponseEntity
class, you can
leverage the @JsonView
annotation from Jackson to activate the serialization view class, like
shown in the following example:
@RestController
public class UserController {
@GetMapping("/user")
@JsonView(User.WithoutPasswordView.class)
public User getUser() {
return new User("eric", "7!jd#h23");
}
}
public class User {
public interface WithoutPasswordView {};
public interface WithPasswordView extends WithoutPasswordView {};
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
@JsonView(WithoutPasswordView.class)
public String getUsername() {
return this.username;
}
@JsonView(WithPasswordView.class)
public String getPassword() {
return this.password;
}
}
@RestController
class UserController {
@GetMapping("/user")
@JsonView(User.WithoutPasswordView::class)
fun getUser() = User("eric", "7!jd#h23")
}
class User(
@JsonView(WithoutPasswordView::class) val username: String,
@JsonView(WithPasswordView::class) val password: String) {
interface WithoutPasswordView
interface WithPasswordView : WithoutPasswordView
}
@JsonView
allows you to use an array of view classes,
but you can only specify one per controller method. If you need to activate multiple views, you can use a
composite interface.
If you want to do the above programmatically, instead of declaring the @JsonView
annotation
wrap the return value with MappingJacksonValue
and use it to provide a serialization view:
@RestController
public class UserController {
@GetMapping("/user")
public MappingJacksonValue getUser() {
User user = new User("eric", "7!jd#h23");
MappingJacksonValue value = new MappingJacksonValue(user);
value.setSerializationView(User.WithoutPasswordView.class);
return value;
}
}
@RestController
class UserController {
@GetMapping("/user")
fun getUser(): MappingJacksonValue {
val value = MappingJacksonValue(User("eric", "7!jd#h23"))
value.serializationView = User.WithoutPasswordView::class.java
return value
}
}
For controllers that use view recognition, you can add a serialization view class to the model, as shown in the following example:
@Controller
public class UserController extends AbstractController {
@GetMapping("/user")
public String getUser(Model model) {
model.addAttribute("user", new User("eric", "7!jd#h23"));
model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class);
return "userView";
}
}
import org.springframework.ui.set
@Controller
class UserController : AbstractController() {
@GetMapping("/user")
fun getUser(model: Model): String {
model["user"] = User("eric", "7!jd#h23")
model[JsonView::class.qualifiedName] = User.WithoutPasswordView::class.java
return "userView"
}
}
GO TO FULL VERSION