Update docs on multipart with RestTemplate

Replace docs on using MultipartBodyBuilder for the RestTemplate with
examples that show MultiValueMap. Originally the idea was to make
MultipartBodyBuilder accessible to the RestTemplate too, but with
support for async parts that's no longer a good fit.

Closes gh-23295
This commit is contained in:
Rossen Stoyanchev 2019-07-19 10:43:50 +01:00
parent 46e5b6f7af
commit 2b94205ba9
2 changed files with 31 additions and 39 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 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.
@ -153,8 +153,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
@ -174,8 +173,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
@ -195,8 +193,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @return the value for the {@code Location} header * @return the value for the {@code Location} header
@ -215,8 +212,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @param responseType the type of the return value * @param responseType the type of the return value
@ -238,8 +234,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @param responseType the type of the return value * @param responseType the type of the return value
@ -260,8 +255,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @param responseType the type of the return value * @param responseType the type of the return value
@ -281,8 +275,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
@ -303,8 +296,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @param uriVariables the variables to expand the template * @param uriVariables the variables to expand the template
@ -324,8 +316,7 @@ public interface RestOperations {
* {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request. * {@link org.springframework.util.MultiValueMap MultiValueMap} to create a multipart request.
* The values in the {@code MultiValueMap} can be any Object representing the body of the part, * The values in the {@code MultiValueMap} can be any Object representing the body of the part,
* or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body * or an {@link org.springframework.http.HttpEntity HttpEntity} representing a part with body
* and headers. The {@code MultiValueMap} can be built conveniently using * and headers.
* {@link org.springframework.http.client.MultipartBodyBuilder MultipartBodyBuilder}.
* @param url the URL * @param url the URL
* @param request the Object to be POSTed (may be {@code null}) * @param request the Object to be POSTed (may be {@code null})
* @return the converted object * @return the converted object

View File

@ -1277,45 +1277,46 @@ to serialize only a subset of the object properties, as the following example sh
[[rest-template-multipart]] [[rest-template-multipart]]
===== Multipart ===== Multipart
To send multipart data, you need to provide a `MultiValueMap<String, ?>` whose values are To send multipart data, you need to provide a `MultiValueMap<String, Object>` whose values
either `Object` instances that represent part content or `HttpEntity` instances that represent the content and may be an `Object` for part content, a `Resource` for a file part, or an `HttpEntity` for
headers for a part. `MultipartBodyBuilder` provides a convenient API to prepare a part content with headers. For example:
multipart request, as the following example shows:
==== ====
[source,java,intent=0] [source,java,intent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]
---- ----
MultipartBodyBuilder builder = new MultipartBodyBuilder(); MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
builder.part("fieldPart", "fieldValue");
builder.part("filePart", new FileSystemResource("...logo.png"));
builder.part("jsonPart", new Person("Jason"));
MultiValueMap<String, HttpEntity<?>> parts = builder.build(); parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
---- ----
==== ====
In most cases, you do not have to specify the `Content-Type` for each part. The content In most cases, you do not have to specify the `Content-Type` for each part. The content
type is determined automatically based on the `HttpMessageConverter` chosen to serialize it type is determined automatically based on the `HttpMessageConverter` chosen to serialize
or, in the case of a `Resource`, based on the file extension. If necessary, you can it or, in the case of a `Resource` based on the file extension. If necessary, you can
explicitly provide the `MediaType` to use for each part through one of the overloaded explicitly provide the `MediaType` with an `HttpEntity` wrapper.
builder `part` methods.
Once the `MultiValueMap` is ready, you can pass it to the `RestTemplate`, as the following example shows: Once the `MultiValueMap` is ready, you can pass it to the `RestTemplate`, as show below:
==== ====
[source,java,intent=0] [source,java,intent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]
---- ----
MultipartBodyBuilder builder = ...; MultiValueMap<String, Object> parts = ...;
template.postForObject("https://example.com/upload", builder.build(), Void.class); template.postForObject("https://example.com/upload", parts, Void.class);
---- ----
==== ====
If the `MultiValueMap` contains at least one non-`String` value, which could also be If the `MultiValueMap` contains at least one non-`String` value, the `Content-Type` is set
represent regular form data (that is, `application/x-www-form-urlencoded`), you need not to `multipart/form-data` by the `FormHttpMessageConverter`. If the `MultiValueMap` has
set the `Content-Type` to `multipart/form-data`. This is always the case when you use `String` values the `Content-Type` is defaulted to `application/x-www-form-urlencoded`.
`MultipartBodyBuilder` which ensures an `HttpEntity` wrapper. If necessary the `Content-Type` may also be set explicitly.
[[rest-async-resttemplate]] [[rest-async-resttemplate]]