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.
|
* 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");
|
* 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.
|
||||||
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.reactive.result.method.annotation;
|
package org.springframework.web.reactive.result.method.annotation;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
@ -75,25 +74,31 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageReaderArgu
|
||||||
boolean isRequired = (requestPart == null || requestPart.required());
|
boolean isRequired = (requestPart == null || requestPart.required());
|
||||||
String name = getPartName(parameter, requestPart);
|
String name = getPartName(parameter, requestPart);
|
||||||
|
|
||||||
Flux<Part> partFlux = getPartValues(name, exchange);
|
Flux<Part> values = exchange.getMultipartData()
|
||||||
if (isRequired) {
|
.flatMapMany(map -> {
|
||||||
partFlux = partFlux.switchIfEmpty(Flux.error(getMissingPartException(name, parameter)));
|
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());
|
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
|
||||||
MethodParameter elementType = adapter != null ? parameter.nested() : parameter;
|
MethodParameter elementType = adapter != null ? parameter.nested() : parameter;
|
||||||
|
|
||||||
if (Part.class.isAssignableFrom(elementType.getNestedParameterType())) {
|
if (Part.class.isAssignableFrom(elementType.getNestedParameterType())) {
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
partFlux = adapter.isMultiValue() ? partFlux : partFlux.take(1);
|
values = adapter.isMultiValue() ? values : values.take(1);
|
||||||
return Mono.just(adapter.fromPublisher(partFlux));
|
return Mono.just(adapter.fromPublisher(values));
|
||||||
}
|
}
|
||||||
else {
|
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);
|
ServerHttpRequest partRequest = new PartServerHttpRequest(exchange.getRequest(), part);
|
||||||
ServerWebExchange partExchange = exchange.mutate().request(partRequest).build();
|
ServerWebExchange partExchange = exchange.mutate().request(partRequest).build();
|
||||||
return readBody(parameter, isRequired, bindingContext, partExchange);
|
return readBody(parameter, isRequired, bindingContext, partExchange);
|
||||||
|
@ -113,12 +118,6 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageReaderArgu
|
||||||
return partName;
|
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) {
|
private ServerWebInputException getMissingPartException(String name, MethodParameter param) {
|
||||||
String reason = "Required request part '" + name + "' is not present";
|
String reason = "Required request part '" + name + "' is not present";
|
||||||
return new ServerWebInputException(reason, param);
|
return new ServerWebInputException(reason, param);
|
||||||
|
|
|
@ -1789,27 +1789,26 @@ Content-Transfer-Encoding: 8bit
|
||||||
... File Data ...
|
... File Data ...
|
||||||
----
|
----
|
||||||
|
|
||||||
You can access the "meta-data" part with `@RequestPart` which would deserialize it from
|
You can access individual parts with `@RequestPart`:
|
||||||
JSON (similar to `@RequestBody`) through one of the configured <<webflux-codecs>>:
|
|
||||||
|
|
||||||
[source,java,indent=0]
|
[source,java,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
@PostMapping("/")
|
@PostMapping("/")
|
||||||
public String handle(**@RequestPart("meta-data") MetaData metadata,
|
public String handle(**@RequestPart("meta-data") Part metadata,
|
||||||
@RequestPart("file-data") FilePart file**) {
|
@RequestPart("file-data") FilePart file**) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
To access multipart data sequentially, in streaming fashion, use `@RequestBody` with
|
To deserialize the raw part content, for example to JSON (similar to `@RequestBody`),
|
||||||
`Flux<Part>` instead. For example:
|
simply declare a concrete target Object, instead of `Part`:
|
||||||
|
|
||||||
[source,java,indent=0]
|
[source,java,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
@PostMapping("/")
|
@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]]
|
[[webflux-ann-requestbody]]
|
||||||
==== @RequestBody
|
==== @RequestBody
|
||||||
|
|
Loading…
Reference in New Issue