Polish @RequestPart support
This commit is contained in:
parent
c1405ef140
commit
94c525cdc8
|
@ -312,6 +312,9 @@ public abstract class MimeTypeUtils {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate a random MIME boundary as bytes, often used in multipart mime types.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
@ -75,25 +74,31 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageReaderArgu
|
|||
boolean isRequired = (requestPart == null || requestPart.required());
|
||||
String name = getPartName(parameter, requestPart);
|
||||
|
||||
Flux<Part> partFlux = getPartValues(name, exchange);
|
||||
if (isRequired) {
|
||||
partFlux = partFlux.switchIfEmpty(Flux.error(getMissingPartException(name, parameter)));
|
||||
Flux<Part> values = exchange.getMultipartData()
|
||||
.flatMapMany(map -> {
|
||||
List<Part> parts = map.get(name);
|
||||
if (CollectionUtils.isEmpty(parts)) {
|
||||
return isRequired ?
|
||||
Flux.error(getMissingPartException(name, parameter)) :
|
||||
Flux.empty();
|
||||
}
|
||||
return Flux.fromIterable(parts);
|
||||
});
|
||||
|
||||
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
|
||||
MethodParameter elementType = adapter != null ? parameter.nested() : parameter;
|
||||
|
||||
if (Part.class.isAssignableFrom(elementType.getNestedParameterType())) {
|
||||
if (adapter != null) {
|
||||
partFlux = adapter.isMultiValue() ? partFlux : partFlux.take(1);
|
||||
return Mono.just(adapter.fromPublisher(partFlux));
|
||||
values = adapter.isMultiValue() ? values : values.take(1);
|
||||
return Mono.just(adapter.fromPublisher(values));
|
||||
}
|
||||
else {
|
||||
return partFlux.next().cast(Object.class);
|
||||
return values.next().cast(Object.class);
|
||||
}
|
||||
}
|
||||
|
||||
return partFlux.next().flatMap(part -> {
|
||||
return values.next().flatMap(part -> {
|
||||
ServerHttpRequest partRequest = new PartServerHttpRequest(exchange.getRequest(), part);
|
||||
ServerWebExchange partExchange = exchange.mutate().request(partRequest).build();
|
||||
return readBody(parameter, isRequired, bindingContext, partExchange);
|
||||
|
@ -113,12 +118,6 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageReaderArgu
|
|||
return partName;
|
||||
}
|
||||
|
||||
private Flux<Part> getPartValues(String name, ServerWebExchange exchange) {
|
||||
return exchange.getMultipartData()
|
||||
.filter(map -> !CollectionUtils.isEmpty(map.get(name)))
|
||||
.flatMapIterable(map -> map.getOrDefault(name, Collections.emptyList()));
|
||||
}
|
||||
|
||||
private ServerWebInputException getMissingPartException(String name, MethodParameter param) {
|
||||
String reason = "Required request part '" + name + "' is not present";
|
||||
return new ServerWebInputException(reason, param);
|
||||
|
|
|
@ -1789,27 +1789,26 @@ Content-Transfer-Encoding: 8bit
|
|||
... File Data ...
|
||||
----
|
||||
|
||||
You can access the "meta-data" part with `@RequestPart` which would deserialize it from
|
||||
JSON (similar to `@RequestBody`) through one of the configured <<webflux-codecs>>:
|
||||
You can access individual parts with `@RequestPart`:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@PostMapping("/")
|
||||
public String handle(**@RequestPart("meta-data") MetaData metadata,
|
||||
public String handle(**@RequestPart("meta-data") Part metadata,
|
||||
@RequestPart("file-data") FilePart file**) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
To access multipart data sequentially, in streaming fashion, use `@RequestBody` with
|
||||
`Flux<Part>` instead. For example:
|
||||
To deserialize the raw part content, for example to JSON (similar to `@RequestBody`),
|
||||
simply declare a concrete target Object, instead of `Part`:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@PostMapping("/")
|
||||
public String handle(**@RequestBody Flux<Part> parts**) {
|
||||
public String handle(**@RequestPart("meta-data") MetaData metadata**) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
@ -1830,6 +1829,29 @@ public String handle(**@Valid** @RequestPart("meta-data") MetaData metadata,
|
|||
}
|
||||
----
|
||||
|
||||
To access all multipart data in as a `MultiValueMap` use `@RequestBody`:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@PostMapping("/")
|
||||
public String handle(**@RequestBody Mono<MultiValueMap<String, Part>> parts**) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
To access multipart data sequentially, in streaming fashion, use `@RequestBody` with
|
||||
`Flux<Part>` instead. For example:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@PostMapping("/")
|
||||
public String handle(**@RequestBody Flux<Part> parts**) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
[[webflux-ann-requestbody]]
|
||||
==== @RequestBody
|
||||
|
|
Loading…
Reference in New Issue