Add explicit support for multipart/mixed in FormHttpMessageConverter
Commit 5008423408
added support for
multipart/* media types in FormHttpMessageConverter, but users still had
to manually register multipart/mixed as a supported media type in order
to POST multipart data with that content type.
This commit removes the need to manually register multipart/mixed as a
supported media type by registering it automatically in
FormHttpMessageConverter. In addition, this commit introduces
MULTIPART_MIXED and MULTIPART_MIXED_VALUE constants in MediaType.
Closes gh-23209
This commit is contained in:
parent
75d1428e24
commit
896496341a
|
@ -44,6 +44,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @author Kazuki Shimizu
|
* @author Kazuki Shimizu
|
||||||
|
* @author Sam Brannen
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc7231#section-3.1.1.1">
|
* @see <a href="https://tools.ietf.org/html/rfc7231#section-3.1.1.1">
|
||||||
* HTTP 1.1: Semantics and Content, section 3.1.1.1</a>
|
* HTTP 1.1: Semantics and Content, section 3.1.1.1</a>
|
||||||
|
@ -288,6 +289,18 @@ public class MediaType extends MimeType implements Serializable {
|
||||||
*/
|
*/
|
||||||
public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data";
|
public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public constant media type for {@code multipart/mixed}.
|
||||||
|
* @since 5.2
|
||||||
|
*/
|
||||||
|
public static final MediaType MULTIPART_MIXED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A String equivalent of {@link MediaType#MULTIPART_MIXED}.
|
||||||
|
* @since 5.2
|
||||||
|
*/
|
||||||
|
public static final String MULTIPART_MIXED_VALUE = "multipart/mixed";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public constant media type for {@code text/event-stream}.
|
* Public constant media type for {@code text/event-stream}.
|
||||||
* @since 4.3.6
|
* @since 4.3.6
|
||||||
|
@ -367,6 +380,7 @@ public class MediaType extends MimeType implements Serializable {
|
||||||
IMAGE_JPEG = new MediaType("image", "jpeg");
|
IMAGE_JPEG = new MediaType("image", "jpeg");
|
||||||
IMAGE_PNG = new MediaType("image", "png");
|
IMAGE_PNG = new MediaType("image", "png");
|
||||||
MULTIPART_FORM_DATA = new MediaType("multipart", "form-data");
|
MULTIPART_FORM_DATA = new MediaType("multipart", "form-data");
|
||||||
|
MULTIPART_MIXED = new MediaType("multipart", "mixed");
|
||||||
TEXT_EVENT_STREAM = new MediaType("text", "event-stream");
|
TEXT_EVENT_STREAM = new MediaType("text", "event-stream");
|
||||||
TEXT_HTML = new MediaType("text", "html");
|
TEXT_HTML = new MediaType("text", "html");
|
||||||
TEXT_MARKDOWN = new MediaType("text", "markdown");
|
TEXT_MARKDOWN = new MediaType("text", "markdown");
|
||||||
|
|
|
@ -52,7 +52,8 @@ import org.springframework.util.StringUtils;
|
||||||
* <p>In other words, this converter can read and write the
|
* <p>In other words, this converter can read and write the
|
||||||
* {@code "application/x-www-form-urlencoded"} media type as
|
* {@code "application/x-www-form-urlencoded"} media type as
|
||||||
* {@link MultiValueMap MultiValueMap<String, String>}, and it can also
|
* {@link MultiValueMap MultiValueMap<String, String>}, and it can also
|
||||||
* write (but not read) the {@code "multipart/form-data"} media type as
|
* write (but not read) the {@code "multipart/form-data"} and
|
||||||
|
* {@code "multipart/mixed"} media types as
|
||||||
* {@link MultiValueMap MultiValueMap<String, Object>}.
|
* {@link MultiValueMap MultiValueMap<String, Object>}.
|
||||||
*
|
*
|
||||||
* <h3>Multipart Data</h3>
|
* <h3>Multipart Data</h3>
|
||||||
|
@ -63,7 +64,9 @@ import org.springframework.util.StringUtils;
|
||||||
* {@code "multipart/mixed"} and {@code "multipart/related"}, as long as the
|
* {@code "multipart/mixed"} and {@code "multipart/related"}, as long as the
|
||||||
* multipart subtype is registered as a {@linkplain #getSupportedMediaTypes
|
* multipart subtype is registered as a {@linkplain #getSupportedMediaTypes
|
||||||
* supported media type} <em>and</em> the desired multipart subtype is specified
|
* supported media type} <em>and</em> the desired multipart subtype is specified
|
||||||
* as the content type when {@linkplain #write writing} the multipart data.
|
* as the content type when {@linkplain #write writing} the multipart data. Note
|
||||||
|
* that {@code "multipart/mixed"} is registered as a supported media type by
|
||||||
|
* default.
|
||||||
*
|
*
|
||||||
* <p>When writing multipart data, this converter uses other
|
* <p>When writing multipart data, this converter uses other
|
||||||
* {@link HttpMessageConverter HttpMessageConverters} to write the respective
|
* {@link HttpMessageConverter HttpMessageConverters} to write the respective
|
||||||
|
@ -85,8 +88,8 @@ import org.springframework.util.StringUtils;
|
||||||
* form.add("field 2", "value 2");
|
* form.add("field 2", "value 2");
|
||||||
* form.add("field 2", "value 3");
|
* form.add("field 2", "value 3");
|
||||||
* form.add("field 3", 4); // non-String form values supported as of 5.1.4
|
* form.add("field 3", 4); // non-String form values supported as of 5.1.4
|
||||||
* restTemplate.postForLocation("https://example.com/myForm", form);
|
*
|
||||||
* </pre>
|
* restTemplate.postForLocation("https://example.com/myForm", form);</pre>
|
||||||
*
|
*
|
||||||
* <p>The following snippet shows how to do a file upload using the
|
* <p>The following snippet shows how to do a file upload using the
|
||||||
* {@code "multipart/form-data"} content type.
|
* {@code "multipart/form-data"} content type.
|
||||||
|
@ -95,33 +98,45 @@ import org.springframework.util.StringUtils;
|
||||||
* MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
|
* MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
|
||||||
* parts.add("field 1", "value 1");
|
* parts.add("field 1", "value 1");
|
||||||
* parts.add("file", new ClassPathResource("myFile.jpg"));
|
* parts.add("file", new ClassPathResource("myFile.jpg"));
|
||||||
* restTemplate.postForLocation("https://example.com/myFileUpload", parts);
|
*
|
||||||
* </pre>
|
* restTemplate.postForLocation("https://example.com/myFileUpload", parts);</pre>
|
||||||
*
|
*
|
||||||
* <p>The following snippet shows how to do a file upload using the
|
* <p>The following snippet shows how to do a file upload using the
|
||||||
* {@code "multipart/mixed"} content type.
|
* {@code "multipart/mixed"} content type.
|
||||||
*
|
*
|
||||||
* <pre class="code">
|
* <pre class="code">
|
||||||
* MediaType multipartMixed = new MediaType("multipart", "mixed");
|
* MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
|
||||||
|
* parts.add("field 1", "value 1");
|
||||||
|
* parts.add("file", new ClassPathResource("myFile.jpg"));
|
||||||
|
*
|
||||||
|
* HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
|
* requestHeaders.setContentType(MediaType.MULTIPART_MIXED);
|
||||||
|
*
|
||||||
|
* restTemplate.postForLocation("https://example.com/myFileUpload",
|
||||||
|
* new HttpEntity<>(parts, requestHeaders));</pre>
|
||||||
|
*
|
||||||
|
* <p>The following snippet shows how to do a file upload using the
|
||||||
|
* {@code "multipart/related"} content type.
|
||||||
|
*
|
||||||
|
* <pre class="code">
|
||||||
|
* MediaType multipartRelated = new MediaType("multipart", "related");
|
||||||
*
|
*
|
||||||
* restTemplate.getMessageConverters().stream()
|
* restTemplate.getMessageConverters().stream()
|
||||||
* .filter(FormHttpMessageConverter.class::isInstance)
|
* .filter(FormHttpMessageConverter.class::isInstance)
|
||||||
* .map(FormHttpMessageConverter.class::cast)
|
* .map(FormHttpMessageConverter.class::cast)
|
||||||
* .findFirst()
|
* .findFirst()
|
||||||
* .orElseThrow(() -> new IllegalStateException("Failed to find FormHttpMessageConverter"))
|
* .orElseThrow(() -> new IllegalStateException("Failed to find FormHttpMessageConverter"))
|
||||||
* .addSupportedMediaTypes(multipartMixed);
|
* .addSupportedMediaTypes(multipartRelated);
|
||||||
*
|
*
|
||||||
* MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
|
* MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
|
||||||
* parts.add("field 1", "value 1");
|
* parts.add("field 1", "value 1");
|
||||||
* parts.add("file", new ClassPathResource("myFile.jpg"));
|
* parts.add("file", new ClassPathResource("myFile.jpg"));
|
||||||
*
|
*
|
||||||
* HttpHeaders requestHeaders = new HttpHeaders();
|
* HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
* requestHeaders.setContentType(multipartMixed);
|
* requestHeaders.setContentType(multipartRelated);
|
||||||
* HttpEntity<MultiValueMap<String, Object>> requestEntity =
|
|
||||||
* new HttpEntity<>(parts, requestHeaders);
|
|
||||||
*
|
*
|
||||||
* restTemplate.postForLocation("https://example.com/myFileUpload", requestEntity);
|
* restTemplate.postForLocation("https://example.com/myFileUpload",
|
||||||
* </pre>
|
* new HttpEntity<>(parts, requestHeaders));</pre>
|
||||||
*
|
*
|
||||||
* <h3>Miscellaneous</h3>
|
* <h3>Miscellaneous</h3>
|
||||||
*
|
*
|
||||||
|
@ -138,13 +153,13 @@ import org.springframework.util.StringUtils;
|
||||||
*/
|
*/
|
||||||
public class FormHttpMessageConverter implements HttpMessageConverter<MultiValueMap<String, ?>> {
|
public class FormHttpMessageConverter implements HttpMessageConverter<MultiValueMap<String, ?>> {
|
||||||
|
|
||||||
private static final MediaType MULTIPART_ALL = new MediaType("multipart", "*");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default charset used by the converter.
|
* The default charset used by the converter.
|
||||||
*/
|
*/
|
||||||
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
static final MediaType MULTIPART_ALL = new MediaType("multipart", "*");
|
||||||
|
|
||||||
private static final MediaType DEFAULT_FORM_DATA_MEDIA_TYPE =
|
private static final MediaType DEFAULT_FORM_DATA_MEDIA_TYPE =
|
||||||
new MediaType(MediaType.APPLICATION_FORM_URLENCODED, DEFAULT_CHARSET);
|
new MediaType(MediaType.APPLICATION_FORM_URLENCODED, DEFAULT_CHARSET);
|
||||||
|
|
||||||
|
@ -162,6 +177,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||||
public FormHttpMessageConverter() {
|
public FormHttpMessageConverter() {
|
||||||
this.supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
|
this.supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
this.supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA);
|
this.supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA);
|
||||||
|
this.supportedMediaTypes.add(MediaType.MULTIPART_MIXED);
|
||||||
|
|
||||||
this.partConverters.add(new ByteArrayHttpMessageConverter());
|
this.partConverters.add(new ByteArrayHttpMessageConverter());
|
||||||
this.partConverters.add(new StringHttpMessageConverter());
|
this.partConverters.add(new StringHttpMessageConverter());
|
||||||
|
|
|
@ -49,7 +49,9 @@ import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;
|
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;
|
||||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||||
|
import static org.springframework.http.MediaType.MULTIPART_MIXED;
|
||||||
import static org.springframework.http.MediaType.TEXT_XML;
|
import static org.springframework.http.MediaType.TEXT_XML;
|
||||||
|
import static org.springframework.http.converter.FormHttpMessageConverter.MULTIPART_ALL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link FormHttpMessageConverter} and
|
* Unit tests for {@link FormHttpMessageConverter} and
|
||||||
|
@ -61,8 +63,6 @@ import static org.springframework.http.MediaType.TEXT_XML;
|
||||||
*/
|
*/
|
||||||
public class FormHttpMessageConverterTests {
|
public class FormHttpMessageConverterTests {
|
||||||
|
|
||||||
private static final MediaType MULTIPART_ALL = new MediaType("multipart", "*");
|
|
||||||
private static final MediaType MULTIPART_MIXED = new MediaType("multipart", "mixed");
|
|
||||||
private static final MediaType MULTIPART_RELATED = new MediaType("multipart", "related");
|
private static final MediaType MULTIPART_RELATED = new MediaType("multipart", "related");
|
||||||
|
|
||||||
private final FormHttpMessageConverter converter = new AllEncompassingFormHttpMessageConverter();
|
private final FormHttpMessageConverter converter = new AllEncompassingFormHttpMessageConverter();
|
||||||
|
@ -80,24 +80,19 @@ public class FormHttpMessageConverterTests {
|
||||||
@Test
|
@Test
|
||||||
public void cannotReadMultipart() {
|
public void cannotReadMultipart() {
|
||||||
// Without custom multipart types supported
|
// Without custom multipart types supported
|
||||||
assertCannotRead(MULTIPART_ALL);
|
asssertCannotReadMultipart();
|
||||||
assertCannotRead(MULTIPART_FORM_DATA);
|
|
||||||
assertCannotRead(MULTIPART_MIXED);
|
|
||||||
assertCannotRead(MULTIPART_RELATED);
|
|
||||||
|
|
||||||
this.converter.addSupportedMediaTypes(MULTIPART_MIXED, MULTIPART_RELATED);
|
this.converter.addSupportedMediaTypes(MULTIPART_RELATED);
|
||||||
|
|
||||||
// With custom multipart types supported
|
// Should still be the case with custom multipart types supported
|
||||||
assertCannotRead(MULTIPART_ALL);
|
asssertCannotReadMultipart();
|
||||||
assertCannotRead(MULTIPART_FORM_DATA);
|
|
||||||
assertCannotRead(MULTIPART_MIXED);
|
|
||||||
assertCannotRead(MULTIPART_RELATED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void canWrite() {
|
public void canWrite() {
|
||||||
assertCanWrite(APPLICATION_FORM_URLENCODED);
|
assertCanWrite(APPLICATION_FORM_URLENCODED);
|
||||||
assertCanWrite(MULTIPART_FORM_DATA);
|
assertCanWrite(MULTIPART_FORM_DATA);
|
||||||
|
assertCanWrite(MULTIPART_MIXED);
|
||||||
assertCanWrite(new MediaType("multipart", "form-data", StandardCharsets.UTF_8));
|
assertCanWrite(new MediaType("multipart", "form-data", StandardCharsets.UTF_8));
|
||||||
assertCanWrite(MediaType.ALL);
|
assertCanWrite(MediaType.ALL);
|
||||||
assertCanWrite(null);
|
assertCanWrite(null);
|
||||||
|
@ -105,26 +100,21 @@ public class FormHttpMessageConverterTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setSupportedMediaTypes() {
|
public void setSupportedMediaTypes() {
|
||||||
assertCannotWrite(MULTIPART_MIXED);
|
|
||||||
assertCannotWrite(MULTIPART_RELATED);
|
assertCannotWrite(MULTIPART_RELATED);
|
||||||
|
|
||||||
List<MediaType> supportedMediaTypes = new ArrayList<>(this.converter.getSupportedMediaTypes());
|
List<MediaType> supportedMediaTypes = new ArrayList<>(this.converter.getSupportedMediaTypes());
|
||||||
supportedMediaTypes.add(MULTIPART_MIXED);
|
|
||||||
supportedMediaTypes.add(MULTIPART_RELATED);
|
supportedMediaTypes.add(MULTIPART_RELATED);
|
||||||
this.converter.setSupportedMediaTypes(supportedMediaTypes);
|
this.converter.setSupportedMediaTypes(supportedMediaTypes);
|
||||||
|
|
||||||
assertCanWrite(MULTIPART_MIXED);
|
|
||||||
assertCanWrite(MULTIPART_RELATED);
|
assertCanWrite(MULTIPART_RELATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addSupportedMediaTypes() {
|
public void addSupportedMediaTypes() {
|
||||||
assertCannotWrite(MULTIPART_MIXED);
|
|
||||||
assertCannotWrite(MULTIPART_RELATED);
|
assertCannotWrite(MULTIPART_RELATED);
|
||||||
|
|
||||||
this.converter.addSupportedMediaTypes(MULTIPART_MIXED, MULTIPART_RELATED);
|
this.converter.addSupportedMediaTypes(MULTIPART_RELATED);
|
||||||
|
|
||||||
assertCanWrite(MULTIPART_MIXED);
|
|
||||||
assertCanWrite(MULTIPART_RELATED);
|
assertCanWrite(MULTIPART_RELATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +276,13 @@ public class FormHttpMessageConverterTests {
|
||||||
assertThat(this.converter.canRead(clazz, mediaType)).as(clazz.getSimpleName() + " : " + mediaType).isTrue();
|
assertThat(this.converter.canRead(clazz, mediaType)).as(clazz.getSimpleName() + " : " + mediaType).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void asssertCannotReadMultipart() {
|
||||||
|
assertCannotRead(MULTIPART_ALL);
|
||||||
|
assertCannotRead(MULTIPART_FORM_DATA);
|
||||||
|
assertCannotRead(MULTIPART_MIXED);
|
||||||
|
assertCannotRead(MULTIPART_RELATED);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertCannotRead(MediaType mediaType) {
|
private void assertCannotRead(MediaType mediaType) {
|
||||||
assertCannotRead(MultiValueMap.class, mediaType);
|
assertCannotRead(MultiValueMap.class, mediaType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
|
||||||
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
|
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
|
||||||
import static org.springframework.http.HttpHeaders.LOCATION;
|
import static org.springframework.http.HttpHeaders.LOCATION;
|
||||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||||
|
import static org.springframework.http.MediaType.MULTIPART_MIXED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
@ -43,7 +44,6 @@ import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||||
*/
|
*/
|
||||||
public class AbstractMockWebServerTestCase {
|
public class AbstractMockWebServerTestCase {
|
||||||
|
|
||||||
protected static final MediaType MULTIPART_MIXED = new MediaType("multipart", "mixed");
|
|
||||||
protected static final MediaType MULTIPART_RELATED = new MediaType("multipart", "related");
|
protected static final MediaType MULTIPART_RELATED = new MediaType("multipart", "related");
|
||||||
|
|
||||||
protected static final MediaType textContentType =
|
protected static final MediaType textContentType =
|
||||||
|
|
|
@ -63,6 +63,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
import static org.junit.Assume.assumeFalse;
|
import static org.junit.Assume.assumeFalse;
|
||||||
import static org.springframework.http.HttpMethod.POST;
|
import static org.springframework.http.HttpMethod.POST;
|
||||||
|
import static org.springframework.http.MediaType.MULTIPART_MIXED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration tests for {@link RestTemplate}.
|
* Integration tests for {@link RestTemplate}.
|
||||||
|
@ -274,15 +275,10 @@ public class RestTemplateIntegrationTests extends AbstractMockWebServerTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void multipartMixed() {
|
public void multipartMixed() throws Exception {
|
||||||
addSupportedMediaTypeToFormHttpMessageConverter(MULTIPART_MIXED);
|
|
||||||
|
|
||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
requestHeaders.setContentType(MULTIPART_MIXED);
|
requestHeaders.setContentType(MULTIPART_MIXED);
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(createMultipartParts(),
|
template.postForLocation(baseUrl + "/multipartMixed", new HttpEntity<>(createMultipartParts(), requestHeaders));
|
||||||
requestHeaders);
|
|
||||||
|
|
||||||
template.postForLocation(baseUrl + "/multipartMixed", requestEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -291,10 +287,7 @@ public class RestTemplateIntegrationTests extends AbstractMockWebServerTestCase
|
||||||
|
|
||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
requestHeaders.setContentType(MULTIPART_RELATED);
|
requestHeaders.setContentType(MULTIPART_RELATED);
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(createMultipartParts(),
|
template.postForLocation(baseUrl + "/multipartRelated", new HttpEntity<>(createMultipartParts(), requestHeaders));
|
||||||
requestHeaders);
|
|
||||||
|
|
||||||
template.postForLocation(baseUrl + "/multipartRelated", requestEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiValueMap<String, Object> createMultipartParts() {
|
private MultiValueMap<String, Object> createMultipartParts() {
|
||||||
|
|
Loading…
Reference in New Issue