Update docs on multipart requests + table of parameters

Issue: SPR-16040
This commit is contained in:
Rossen Stoyanchev 2018-01-16 11:31:22 -05:00
parent 65a167f7fd
commit b97fa4a5ee
2 changed files with 231 additions and 185 deletions

View File

@ -964,6 +964,9 @@ Java 8+: `java.time.ZoneId`
|For access to Servlet request parameters. Parameter values are converted to the declared
method argument type. See <<webflux-ann-requestparam>>.
Note that use of `@RequestParam` is optional, e.g. to set its attributes.
See "Any other argument" further below in this table.
|`@RequestHeader`
|For access to request headers. Header values are converted to the declared method argument
type. See <<webflux-ann-requestheader>>.
@ -987,40 +990,48 @@ Supports reactive types.
// TODO: See <<webflux-multipart-forms-non-browsers>> and <<webflux-multipart>>.
|`java.util.Map`, `org.springframework.ui.Model`, `org.springframework.ui.ModelMap`
|For access and updates of the implicit model that is exposed to the web view.
|For access to the model that is used in HTML controllers and exposed to templates as
part of view rendering.
|Command or form object (with optional `@ModelAttribute`)
|Command object whose properties to bind to request parameters -- via setters or directly to
fields, with customizable type conversion, depending on `@InitBinder` methods and/or the
HandlerAdapter configuration (see the `webBindingInitializer` property on
`RequestMappingHandlerAdapter`).
|`@ModelAttribute`
|For access to an existing attribute in the model (instantiated if not present) with
data binding and validation applied. See <<webflux-ann-modelattrib-method-args>> as well
as <<webflux-ann-modelattrib-methods>> and <<webflux-ann-initbinder>>.
Command objects along with their validation results are exposed as model attributes, by
default using the command class name - e.g. model attribute "orderAddress" for a command
object of type "some.package.OrderAddress". `@ModelAttribute` can be used to customize the
model attribute name.
Supports reactive types.
Note that use of `@ModelAttribute` is optional, e.g. to set its attributes.
See "Any other argument" further below in this table.
|`Errors`, `BindingResult`
|Validation results for the command/form object data binding; this argument must be
declared immediately after the command/form object in the controller method signature.
|For access to errors from the data binding and validation applied to a command object;
this argument must be declared immediately after a command object (i.e.
`@ModelAttribute` argument). If this is not declared in the controller method signature,
errors result in a `BindException`. See <<webflux-ann-modelattrib-method-args>> for more
details.
|`SessionStatus`
|`SessionStatus` + class-level `@SessionAttributes`
|For marking form processing complete which triggers cleanup of session attributes
declared through a class-level `@SessionAttributes` annotation.
declared through a class-level `@SessionAttributes` annotation. See
<<webflux-ann-sessionattributes>> for more details.
|`UriComponentsBuilder`
|For preparing a URL relative to the current request's host, port, scheme, context path, and
the literal part of the servlet mapping also taking into account `Forwarded` and
`X-Forwarded-*` headers.
// See <<webflux-uri-building>>.
|`@SessionAttribute`
|For access to any session attribute; in contrast to model attributes stored in the session
as a result of a class-level `@SessionAttributes` declaration.
as a result of a class-level `@SessionAttributes` declaration. See
<<webflux-ann-sessionattribute>> for more details.
|`@RequestAttribute`
|For access to request attributes.
|For access to request attributes. See <<webflux-ann-requestattrib>> for more details.
|Any other argument
|If a method argument is not matched to any of the above, by default it is resolved as
an `@RequestParam` if it is a simple type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
or as an `@ModelAttribute` otherwise.
|===
@ -1061,7 +1072,14 @@ programmatically enrich the model by declaring a `Model` argument (see above).
|`java.util.Map`, `org.springframework.ui.Model`
|Attributes to be added to the implicit model with the view name implicitly determined
from the request path.
based on the request path.
|`@ModelAttribute`
|An attribute to be added to the model with the view name implicitly determined based
on the request path.
Note that `@ModelAttribute` is optional. See "Any other return value" further below in
this table.
|`Rendering`
|An API for model and view rendering scenarios.
@ -1081,11 +1099,12 @@ REST controllers, or default view name selection for HTML controllers.
to be written (however `text/event-stream` must be requested or declared in the mapping
through the produces attribute).
|Any other return type
|A single model attribute to be added to the implicit model with the view name implicitly
determined through a `RequestToViewNameTranslator`; the attribute name may be specified
through a method-level `@ModelAttribute` or otherwise a name is selected based on the
class name of the return type.
|Any other return value
|If a return value is not matched to any of the above, by default it is treated as a view
name, if it is `String` or `void` (default view name selection applies); or as a model
attribute to be added to the model, unless it is a simple type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty]
in which case it remains unresolved.
|===
@ -1145,6 +1164,12 @@ When an `@RequestParam` annotation is declared as `Map<String, String>` or
`MultiValueMap<String, String>` argument, the map is populated with all request
parameters.
Note that use of `@RequestParam` is optional, e.g. to set its attributes.
By default any argument that is a simple value type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
and is not resolved by any other argument resolver, is treated as if it was annotated
with `@RequestParam`.
[[webflux-ann-requestheader]]
==== @RequestHeader
@ -1231,7 +1256,7 @@ Type conversion is applied automatically if the target method parameter type is
Use the `@ModelAttribute` annotation on a method argument to access an attribute from the
model, or have it instantiated if not present. The model attribute is also overlaid with
values query parameters for form fields whose names match to field names. This is
values of query parameters and form fields whose names match to field names. This is
referred to as data binding and it saves you from having to deal with parsing and
converting individual query parameters and form fields. For example:
@ -1314,6 +1339,12 @@ reactive type:
}
----
Note that use of `@ModelAttribute` is optional, e.g. to set its attributes.
By default any argument that is not a simple value type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
and is not resolved by any other argument resolver, is treated as if it was annotated
with `@ModelAttribute`.
[[webflux-ann-sessionattributes]]
==== @SessionAttributes
@ -1374,7 +1405,7 @@ use the `@SessionAttribute` annotation on a method parameter:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RequestMapping("/")
@GetMapping("/")
public String handle(**@SessionAttribute** User user) {
// ...
}
@ -1388,6 +1419,23 @@ workflow consider using `SessionAttributes` as described in
<<webflux-ann-sessionattributes>>.
[[webflux-ann-requestattrib]]
==== @RequestAttribute
[.small]#<<web.adoc#mvc-ann-requestattrib,Same in Spring MVC>>#
Similar to `@SessionAttribute` the `@RequestAttribute` annotation can be used to
access pre-existing request attributes created earlier, e.g. by a `WebFilter`:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@GetMapping("/")
public String handle(**@RequestAttribute** Client client) {
// ...
}
----
[[webflux-ann-modelattrib-methods]]
=== Model Methods

View File

@ -858,52 +858,40 @@ request with a simple request parameter.
[[mvc-multipart]]
=== Multipart requests
=== Multipart resolver
Spring has built-in support for multipart requests including file uploads.
You enable this multipart support with pluggable `MultipartResolver` objects, defined in the
`org.springframework.web.multipart` package. Spring provides one `MultipartResolver`
implementation for use with http://jakarta.apache.org/commons/fileupload[__Commons
FileUpload__] and another for use with Servlet 3.0 multipart request parsing.
`MultipartResolver` from the `org.springframework.web.multipart` package is a strategy
for parsing multipart requests including file uploads. There is one implementation
based on http://jakarta.apache.org/commons/fileupload[__Commons FileUpload__] and another
based on Servlet 3.0 multipart request parsing.
By default, Spring does no multipart handling, because some developers want to handle
multiparts themselves. You enable Spring multipart handling by adding a multipart
resolver to the web application's context. Each request is inspected to see if it
contains a multipart. If no multipart is found, the request continues as expected. If a
multipart is found in the request, the `MultipartResolver` that has been declared in
your context is used. After that, the multipart attribute in your request is treated
like any other attribute.
To enable multipart handling, you need declare a `MultipartResolver` bean in your
`DispatcherServlet` Spring configuration with the name "multipartResolver".
The `DispatcherServlet` detects it and applies it to incoming request. When a POST with
content-type of "multipart/form-data" is received, the resolver parses the content and
wraps the current `HttpServletRequest` as `MultipartHttpServletRequest` in order to
provide access to resolved parts in addition to exposing them as request parameters.
[[mvc-multipart-resolver-commons]]
==== __Commons FileUpload__
==== Apache FileUpload
To use Apache Commons FileUpload, configure a bean of type `CommonsMultipartResolver` with
the name `multipartResolver`. Of course you also need to have `commons-fileupload` as a
dependency on your classpath.
When the Spring `DispatcherServlet` detects a multipart request, it activates the
resolver that has been declared in your context and hands over the request. The resolver
then wraps the current `HttpServletRequest` into a `MultipartHttpServletRequest` that
supports multipart file uploads. Using the `MultipartHttpServletRequest`, you can get
information about the multiparts contained by this request and actually get access to
the multipart files themselves in your controllers.
To use Apache Commons FileUpload, simply configure a bean of type
`CommonsMultipartResolver` with the name `multipartResolver`. Of course you also need to
have `commons-fileupload` as a dependency on your classpath.
[[mvc-multipart-resolver-standard]]
==== __Servlet 3.0__
==== Servlet 3.0
In order to use Servlet 3.0 based multipart parsing, you need to mark the
`DispatcherServlet` with a `"multipart-config"` section in `web.xml`, or with a
`javax.servlet.MultipartConfigElement` in programmatic Servlet registration, or in case
of a custom Servlet class possibly with a `javax.servlet.annotation.MultipartConfig`
annotation on your Servlet class. Configuration settings such as maximum sizes or
storage locations need to be applied at that Servlet registration level as Servlet 3.0
does not allow for those settings to be done from the MultipartResolver.
To use Servlet 3.0 multipart support, you need to register the `DispatcherServlet`
accordingly. In programmatic Servlet registration, set a `MultipartConfigElement` on the
Servlet registration. In `web.xml`, add a `"<multipart-config>"` section. Configuration
settings such as maximum sizes or storage locations need to be applied at this level
since Servlet 3.0 API does not make it possible for the `MultipartResolver` to do so.
Once Servlet 3.0 multipart parsing has been enabled in one of the above mentioned ways
you can add a bean of type `StandardServletMultipartResolver` and with the name
`multipartResolver` to your Spring configuration.
Once the Servlet 3.0 configuration is in place, simply add a bean of type
`StandardServletMultipartResolver` with the name `multipartResolver`.
@ -1593,6 +1581,9 @@ Java 8+: `java.time.ZoneId`
|For access to Servlet request parameters. Parameter values are converted to the declared
method argument type. See <<mvc-ann-requestparam>>.
Note that use of `@RequestParam` is optional, e.g. to set its attributes.
See "Any other argument" further below in this table.
|`@RequestHeader`
|For access to request headers. Header values are converted to the declared method argument
type. See <<mvc-ann-requestheader>>.
@ -1611,46 +1602,55 @@ See <<mvc-ann-httpentity>>.
|`@RequestPart`
|For access to a part in a "multipart/form-data" request.
See <<mvc-multipart-forms-non-browsers>> and <<mvc-multipart>>.
See <<mvc-multipart-forms>>.
|`java.util.Map`, `org.springframework.ui.Model`, `org.springframework.ui.ModelMap`
|For access and updates of the implicit model that is exposed to the web view.
|For access to the model that is used in HTML controllers and exposed to templates as
part of view rendering.
|`RedirectAttributes`
|Specify attributes to use in case of a redirect -- i.e. to be appended to the query
string, and/or flash attributes to be stored temporarily until the request after redirect.
See <<mvc-redirecting-passing-data>> and <<mvc-flash-attributes>>.
|Command or form object (with optional `@ModelAttribute`)
|Command object whose properties to bind to request parameters -- via setters or directly to
fields, with customizable type conversion, depending on `@InitBinder` methods and/or the
HandlerAdapter configuration (see the `webBindingInitializer` property on
`RequestMappingHandlerAdapter`).
|`@ModelAttribute`
|For access to an existing attribute in the model (instantiated if not present) with
data binding and validation applied. See <<mvc-ann-modelattrib-method-args>> as well as
<<mvc-ann-modelattrib-methods>> and <<mvc-ann-initbinder>>.
Command objects along with their validation results are exposed as model attributes, by
default using the command class name - e.g. model attribute "orderAddress" for a command
object of type "some.package.OrderAddress". `@ModelAttribute` can be used to customize the
model attribute name.
Note that use of `@ModelAttribute` is optional, e.g. to set its attributes.
See "Any other argument" further below in this table.
|`Errors`, `BindingResult`
|Validation results for the command/form object data binding; this argument must be
declared immediately after the command/form object in the controller method signature.
|For access to errors from the data binding and validation applied to a command object;
this argument must be declared immediately after a command object (i.e.
`@ModelAttribute` argument). If this is not declared in the controller method signature,
errors result in a `BindException`. See <<mvc-ann-modelattrib-method-args>> for more
details.
|`SessionStatus`
|`SessionStatus` + class-level `@SessionAttributes`
|For marking form processing complete which triggers cleanup of session attributes
declared through a class-level `@SessionAttributes` annotation.
declared through a class-level `@SessionAttributes` annotation. See
<<mvc-ann-sessionattributes>> for more details.
|`UriComponentsBuilder`
|For preparing a URL relative to the current request's host, port, scheme, context path, and
the literal part of the servlet mapping also taking into account `Forwarded` and
`X-Forwarded-*` headers.
`X-Forwarded-*` headers. See <<mvc-uri-building>>.
|`@SessionAttribute`
|For access to any session attribute; in contrast to model attributes stored in the session
as a result of a class-level `@SessionAttributes` declaration.
as a result of a class-level `@SessionAttributes` declaration. See
<<mvc-ann-sessionattribute>> for more details.
|`@RequestAttribute`
|For access to request attributes.
|For access to request attributes. See <<mvc-ann-requestattrib>> for more details.
|Any other argument
|If a method argument is not matched to any of the above, by default it is resolved as
an `@RequestParam` if it is a simple type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
or as an `@ModelAttribute` otherwise.
|===
@ -1691,6 +1691,13 @@ programmatically enrich the model by declaring a `Model` argument (see above).
|Attributes to be added to the implicit model with the view name implicitly determined
through a `RequestToViewNameTranslator`.
|`@ModelAttribute`
|An attribute to be added to the model with the view name implicitly determined through
a `RequestToViewNameTranslator`.
Note that `@ModelAttribute` is optional. See "Any other return value" further below in
this table.
|`ModelAndView` object
|The view and model attributes to use, and optionally a response status.
@ -1735,11 +1742,13 @@ completion of each write.
See <<mvc-ann-async-reactive-types>>.
|Any other return type
|A single model attribute to be added to the implicit model with the view name implicitly
determined through a `RequestToViewNameTranslator`; the attribute name may be specified
through a method-level `@ModelAttribute` or otherwise a name is selected based on the
class name of the return type.
|Any other return value
|If a return value is not matched to any of the above, by default it is treated as a view
name, if it is `String` or `void` (default view name selection via
`RequestToViewNameTranslator` applies); or as a model attribute to be added to the model,
unless it is a simple type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty]
in which case it remains unresolved.
|===
@ -1799,6 +1808,12 @@ When an `@RequestParam` annotation is declared as `Map<String, String>` or
`MultiValueMap<String, String>` argument, the map is populated with all request
parameters.
Note that use of `@RequestParam` is optional, e.g. to set its attributes.
By default any argument that is a simple value type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
and is not resolved by any other argument resolver, is treated as if it was annotated
with `@RequestParam`.
[[mvc-ann-requestheader]]
==== @RequestHeader
@ -1985,84 +2000,12 @@ Validation can be applied automatically after data binding by adding the
}
----
Note that use of `@ModelAttribute` is optional, e.g. to set its attributes.
By default any argument that is not a simple value type, as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty],
and is not resolved by any other argument resolver, is treated as if it was annotated
with `@ModelAttribute`.
[[mvc-multipart-forms]]
==== File upload
After the `MultipartResolver` completes its job, the request is processed like any
other. First, create a form with a file input that will allow the user to upload a form.
The encoding attribute ( `enctype="multipart/form-data"`) lets the browser know how to
encode the form as multipart request:
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<html>
<head>
<title>Upload a file please</title>
</head>
<body>
<h1>Please upload a file</h1>
<form method="post" action="/form" enctype="multipart/form-data">
<input type="text" name="name"/>
<input type="file" name="file"/>
<input type="submit"/>
</form>
</body>
</html>
----
The next step is to create a controller that handles the file upload. This controller is
very similar to a <<mvc-ann-controller,normal annotated `@Controller`>>, except that we
use `MultipartHttpServletRequest` or `MultipartFile` in the method parameters:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@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";
}
}
----
Note how the `@RequestParam` method parameters map to the input elements declared in the
form. In this example, nothing is done with the `byte[]`, but in practice you can save
it in a database, store it on the file system, and so on.
When using Servlet 3.0 multipart parsing you can also use `javax.servlet.http.Part` for
the method parameter:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") Part file) {
InputStream inputStream = file.getInputStream();
// store bytes from uploaded file somewhere
return "redirect:uploadSuccess";
}
}
----
[[mvc-ann-sessionattributes]]
@ -2142,14 +2085,16 @@ workflow consider using `SessionAttributes` as described in
[[mvc-ann-requestattrib]]
==== @RequestAttribute
[.small]#<<web-reactive.adoc#webflux-ann-requestattrib,Same in Spring WebFlux>>#
Similar to `@SessionAttribute` the `@RequestAttribute` annotation can be used to
access pre-existing request attributes created by a filter or interceptor:
access pre-existing request attributes created earlier, e.g. by a Servlet `Filter`
or `HandlerInterceptor`:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RequestMapping("/")
@GetMapping("/")
public String handle(**@RequestAttribute** Client client) {
// ...
}
@ -2245,14 +2190,79 @@ Therefore the use of flash attributes is recommended mainly for redirect scenari
****
[[mvc-multipart-forms-non-browsers]]
==== @RequestPart
[[mvc-multipart-forms]]
==== Multipart
After a `MultipartResolver` has been <<mvc-multipart,enabled>>, the content of POST
requests with "multipart/form-data" is parsed and accessible as regular request
parameters. In the example below we access one regular form field and one uploaded
file:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@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";
}
}
----
[NOTE]
====
When using Servlet 3.0 multipart parsing you can also use `javax.servlet.http.Part` as
a method argument instead of Spring's `MultipartFile`.
====
Multipart content can also be used as part of data binding to a
<<mvc-ann-modelattrib-method-args,command object>>. For example the above form field
and file could have been fields on a form object:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
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";
}
}
----
Multipart requests can also be submitted from non-browser clients in a RESTful service
scenario. All of the above examples and configuration apply here as well. However,
unlike browsers that typically submit files and simple form fields, a programmatic
client can also send more complex data of a specific content type -- for example a
multipart request with a file and second part with JSON formatted data:
scenario with more types of content. For example a file along with JSON:
[literal]
[subs="verbatim,quotes"]
@ -2275,17 +2285,10 @@ Content-Transfer-Encoding: 8bit
... File Data ...
----
You could access the part named "meta-data" with a `@RequestParam("meta-data") String
metadata` controller method argument. However, you would probably prefer to accept a
strongly typed object initialized from the JSON formatted data in the body of the
request part, very similar to the way `@RequestBody` converts the body of a
non-multipart request to a target object with the help of an
<<integration.adoc#rest-message-conversion,HttpMessageConverter>>.
You can use the `@RequestPart` annotation instead of the `@RequestParam` annotation for
this purpose. It allows you to have the content of a specific multipart passed through
an `HttpMessageConverter` taking into consideration the `'Content-Type'` header of the
multipart:
You can access the "meta-data" part with `@RequestParam` as a `String` but you'll
probably want it deserialized from JSON (similar to `@RequestBody`). Use the
`@RequestPart` annotation to access a multipart after converting it with an
<<integration.adoc#rest-message-conversion,HttpMessageConverter>>:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -2299,11 +2302,6 @@ multipart:
}
----
Notice how `MultipartFile` method arguments can be accessed with `@RequestParam` or with
`@RequestPart` interchangeably. However, the `@RequestPart("meta-data") MetaData` method
argument in this case is read as JSON content based on its `'Content-Type'` header and
converted with the help of the `MappingJackson2HttpMessageConverter`.
[[mvc-ann-requestbody]]
==== @RequestBody