Support @RequestBody Flux<Part> in WebFlux

This commit turns the Synchronoss NIO Multipart HttpMessageReader into
a reader of Flux<Part> and creates a separate reader that aggregates
the parts into a MultiValueMap<String, Part>.

Issue: SPR-14546
This commit is contained in:
Rossen Stoyanchev
2017-05-03 17:25:49 -04:00
parent d43dfc7bae
commit b5089ac092
9 changed files with 198 additions and 57 deletions

View File

@@ -103,7 +103,7 @@ public class DelegatingWebFluxConfigurationTests {
verify(webFluxConfigurer).configureArgumentResolvers(any());
assertSame(formatterRegistry.getValue(), initializerConversionService);
assertEquals(10, codecsConfigurer.getValue().getReaders().size());
assertEquals(11, codecsConfigurer.getValue().getReaders().size());
}
@Test

View File

@@ -127,7 +127,7 @@ public class WebFluxConfigurationSupportTests {
assertNotNull(adapter);
List<HttpMessageReader<?>> readers = adapter.getMessageCodecConfigurer().getReaders();
assertEquals(10, readers.size());
assertEquals(11, readers.size());
assertHasMessageReader(readers, forClass(byte[].class), APPLICATION_OCTET_STREAM);
assertHasMessageReader(readers, forClass(ByteBuffer.class), APPLICATION_OCTET_STREAM);

View File

@@ -16,8 +16,12 @@
package org.springframework.web.reactive.result.method.annotation;
import java.util.Map;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@@ -35,6 +39,7 @@ import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.DispatcherHandler;
@@ -68,14 +73,10 @@ public class MultipartIntegrationTests extends AbstractHttpHandlerIntegrationTes
}
@Test
public void part() {
test("/part");
}
private void test(String uri) {
public void requestPart() {
Mono<ClientResponse> result = webClient
.post()
.uri(uri)
.uri("/requestPart")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(generateBody()))
.exchange();
@@ -86,6 +87,37 @@ public class MultipartIntegrationTests extends AbstractHttpHandlerIntegrationTes
.verifyComplete();
}
@Test
public void requestBodyMap() {
Mono<String> result = webClient
.post()
.uri("/requestBodyMap")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(generateBody()))
.retrieve()
.bodyToMono(String.class);
StepVerifier.create(result)
.consumeNextWith(body -> assertEquals("Map[barPart,fooPart]", body))
.verifyComplete();
}
@Test
public void requestBodyFlux() {
Mono<String> result = webClient
.post()
.uri("/requestBodyFlux")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(generateBody()))
.retrieve()
.bodyToMono(String.class);
StepVerifier.create(result)
.consumeNextWith(body -> assertEquals("Flux[barPart,fooPart]", body))
.verifyComplete();
}
private MultiValueMap<String, Object> generateBody() {
HttpHeaders fooHeaders = new HttpHeaders();
fooHeaders.setContentType(MediaType.TEXT_PLAIN);
@@ -102,11 +134,22 @@ public class MultipartIntegrationTests extends AbstractHttpHandlerIntegrationTes
@SuppressWarnings("unused")
static class MultipartController {
@PostMapping("/part")
@PostMapping("/requestPart")
void part(@RequestPart Part fooPart) {
assertEquals("foo.txt", fooPart.getFilename().get());
}
@PostMapping("/requestBodyMap")
Mono<String> part(@RequestBody Mono<MultiValueMap<String, Part>> parts) {
return parts.map(map -> map.toSingleValueMap().entrySet().stream()
.map(Map.Entry::getKey).sorted().collect(Collectors.joining(",", "Map[", "]")));
}
@PostMapping("/requestBodyFlux")
Mono<String> part(@RequestBody Flux<Part> parts) {
return parts.map(Part::getName).collectList()
.map(names -> names.stream().sorted().collect(Collectors.joining(",", "Flux[", "]")));
}
}
@Configuration