Support incoming application/x-www-form-urlencoded content

Fixes #129
This commit is contained in:
bishoy
2018-03-20 08:31:28 +02:00
committed by Dave Syer
parent c2568ccabe
commit 0e41b8acc5
6 changed files with 174 additions and 77 deletions

View File

@@ -16,19 +16,13 @@
package org.springframework.cloud.function.web.flux;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import org.springframework.cloud.function.context.catalog.FunctionInspector;
import org.springframework.cloud.function.context.message.MessageUtils;
import org.springframework.cloud.function.web.flux.constants.WebRequestConstants;
import org.springframework.cloud.function.web.flux.request.FluxFormRequest;
import org.springframework.cloud.function.web.flux.request.FluxRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -38,10 +32,15 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* @author Dave Syer
* @author Mark Fisher
@@ -68,18 +67,21 @@ public class FunctionController {
@PostMapping(path = "/**")
@ResponseBody
public ResponseEntity<Publisher<?>> post(WebRequest request,
@RequestBody FluxRequest<?> body) {
public ResponseEntity<Publisher<?>> post(WebRequest request, @RequestBody FluxRequest<?> body) {
@SuppressWarnings("unchecked")
Function<Flux<?>, Flux<?>> function = (Function<Flux<?>, Flux<?>>) request
.getAttribute(WebRequestConstants.FUNCTION, WebRequest.SCOPE_REQUEST);
@SuppressWarnings("unchecked")
Consumer<Flux<?>> consumer = (Consumer<Flux<?>>) request
.getAttribute(WebRequestConstants.CONSUMER, WebRequest.SCOPE_REQUEST);
Boolean single = (Boolean) request.getAttribute(WebRequestConstants.INPUT_SINGLE,
WebRequest.SCOPE_REQUEST);
Boolean single = (Boolean) request
.getAttribute(WebRequestConstants.INPUT_SINGLE, WebRequest.SCOPE_REQUEST);
FluxFormRequest form = FluxFormRequest.from(request.getParameterMap());
if (function != null) {
Flux<?> flux = body.flux();
Flux<?> flux = body.body() == null ? form.flux() : body.flux();
if (debug) {
flux = flux.log();
}
@@ -90,11 +92,11 @@ public class FunctionController {
if (logger.isDebugEnabled()) {
logger.debug("Handled POST with function");
}
return ResponseEntity.ok().body(
debug ? result.log() : response(request, function, single, result));
return ResponseEntity.ok().body(debug ? result.log() : response(request, function, single, result));
}
if (consumer != null) {
Flux<?> flux = body.flux().cache(); // send a copy back to the caller
Flux<?> flux = body.body() == null ? form.flux().cache() : body.flux().cache(); // send a copy back to the caller
if (debug) {
flux = flux.log();
}
@@ -104,18 +106,19 @@ public class FunctionController {
}
return ResponseEntity.status(HttpStatus.ACCEPTED).body(flux);
}
throw new IllegalArgumentException("no such function");
}
private Publisher<?> response(WebRequest request, Object handler, Boolean single,
Flux<?> result) {
private Publisher<?> response(WebRequest request, Object handler, Boolean single, Flux<?> result) {
if (single != null && single && isOutputSingle(handler)) {
request.setAttribute(WebRequestConstants.OUTPUT_SINGLE, true,
WebRequest.SCOPE_REQUEST);
request.setAttribute(WebRequestConstants.OUTPUT_SINGLE, true, WebRequest.SCOPE_REQUEST);
return Mono.from(result);
}
request.setAttribute(WebRequestConstants.OUTPUT_SINGLE, false,
WebRequest.SCOPE_REQUEST);
request.setAttribute(WebRequestConstants.OUTPUT_SINGLE, false, WebRequest.SCOPE_REQUEST);
return result;
}
@@ -128,10 +131,7 @@ public class FunctionController {
if (wrapper == type) {
return true;
}
if (Mono.class.equals(wrapper) || Optional.class.equals(wrapper)) {
return true;
}
return false;
return Mono.class.equals(wrapper) || Optional.class.equals(wrapper);
}
@GetMapping(path = "/**")
@@ -143,8 +143,9 @@ public class FunctionController {
@SuppressWarnings("unchecked")
Supplier<Flux<?>> supplier = (Supplier<Flux<?>>) request
.getAttribute(WebRequestConstants.SUPPLIER, WebRequest.SCOPE_REQUEST);
String argument = (String) request.getAttribute(WebRequestConstants.ARGUMENT,
WebRequest.SCOPE_REQUEST);
String argument = (String) request
.getAttribute(WebRequestConstants.ARGUMENT, WebRequest.SCOPE_REQUEST);
if (function != null) {
return value(function, argument);
}

View File

@@ -18,9 +18,8 @@ package org.springframework.cloud.function.web.flux.constants;
/**
* Common storage for web request attribute names (in a separate package to avoid cycles).
*
* @author Dave Syer
*
* @author Dave Syer
*/
public abstract class WebRequestConstants {
@@ -32,7 +31,8 @@ public abstract class WebRequestConstants {
+ ".supplier";
public static final String ARGUMENT = WebRequestConstants.class.getName()
+ ".argument";
public static final String HANDLER = WebRequestConstants.class.getName() + ".handler";
public static final String HANDLER = WebRequestConstants.class.getName()
+ ".handler";
public static final String INPUT_SINGLE = WebRequestConstants.class.getName()
+ ".input_single";
public static final String OUTPUT_SINGLE = WebRequestConstants.class.getName()

View File

@@ -0,0 +1,41 @@
package org.springframework.cloud.function.web.flux.request;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Flux;
import java.util.Arrays;
import java.util.Map;
public class FluxFormRequest<K, V> {
private Map<K, V[]> map;
public FluxFormRequest(Map<K, V[]> map) {
this.map = map;
}
public static <K, V> FluxFormRequest<K, V> from(Map<K, V[]> map) {
return new FluxFormRequest<>(map);
}
public Flux<MultiValueMap<K, V>> flux() {
return Flux.just(buildMap());
}
public MultiValueMap<K, V> body() {
return buildMap();
}
private MultiValueMap<K, V> buildMap() {
if (map == null)
return null;
MultiValueMap<K, V> result = new LinkedMultiValueMap<>();
map.forEach((key, values) -> result.put(key, Arrays.asList(values)));
return result;
}
}