move to spring 5 multipart formdata support

This commit is contained in:
Spencer Gibb
2017-05-02 12:44:45 -06:00
parent a353d16c0c
commit 1ff978fba0
4 changed files with 46 additions and 75 deletions

View File

@@ -90,7 +90,19 @@
<dependency>
<groupId>org.synchronoss.cloud</groupId>
<artifactId>nio-multipart-parser</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.0-rc1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.0-rc1</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@@ -40,6 +40,7 @@ import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
@@ -49,7 +50,6 @@ import com.netflix.loadbalancer.ServerList;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
import static org.springframework.cloud.gateway.test.TestUtils.parseMultipart;
import reactor.core.publisher.Mono;
@@ -128,14 +128,14 @@ public class BaseWebClientTests {
return map;
}
@RequestMapping(value = "/post", consumes = "multipart/form-data")
public Mono<Map<String, Object>> postFormData(ServerWebExchange exchange,
@RequestBody(required = false) String body) {
@RequestMapping(value = "/post", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Map<String, Object>> postFormData(//ServerWebExchange exchange,
// @RequestParam Map<String, Part> parts
/*@RequestBody(required = false) String body*/) {
HashMap<String, Object> ret = new HashMap<>();
HashMap<String, Object> files = parseMultipart(exchange, body);
// HashMap<String, Object> files = parseMultipart(exchange, null);
ret.put("files", files);
// ret.put("files", files);
return Mono.just(ret);
}

View File

@@ -20,6 +20,7 @@ package org.springframework.cloud.gateway.test;
import java.nio.charset.Charset;
import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootConfiguration;
@@ -29,15 +30,11 @@ import org.springframework.context.annotation.Import;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.BodyInserters;
import static org.assertj.core.api.Assertions.assertThat;
@@ -79,24 +76,34 @@ public class FormIntegrationTests extends BaseWebClientTests {
}
@Test
@Ignore //FIXME: java.lang.IllegalStateException: Only one connection receive subscriber allowed.
public void multipartFormDataWorks() {
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
form.add("file", new ClassPathResource("1x1.png"));
RestTemplate restTemplate = new RestTemplate();
ClassPathResource img = new ClassPathResource("1x1.png");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.setContentType(MediaType.IMAGE_PNG);
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(form, headers);
HttpEntity<ClassPathResource> entity = new HttpEntity<>(img, headers);
ResponseEntity<Map> response = restTemplate.exchange(baseUri + "/post", HttpMethod.POST, entity, Map.class);
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("imgpart", entity);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
Map<String, Object> files = getMap(response.getBody(), "files");
assertThat(files).containsKey("file");
String file = (String) files.get("file");
assertThat(file).startsWith("data:").contains(";base64,");
Mono<Map> result = webClient.post()
.uri("/post")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(parts))
.exchange()
.flatMap(response -> response.body(toMono(Map.class)));
StepVerifier.create(result)
.consumeNextWith(map -> {
Map<String, Object> files = getMap(map, "files");
assertThat(files).containsKey("file");
String file = (String) files.get("file");
assertThat(file).startsWith("data:").contains(";base64,");
})
.expectComplete()
.verify(DURATION);
}
@EnableAutoConfiguration

View File

@@ -17,29 +17,11 @@
package org.springframework.cloud.gateway.test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Base64Utils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.server.ServerWebExchange;
import org.synchronoss.cloud.nio.multipart.AbstractNioMultipartListener;
import org.synchronoss.cloud.nio.multipart.Multipart;
import org.synchronoss.cloud.nio.multipart.MultipartContext;
import org.synchronoss.cloud.nio.multipart.NioMultipartParser;
import org.synchronoss.cloud.nio.stream.storage.StreamStorage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.ClientResponse;
import static org.assertj.core.api.Assertions.assertThat;
/**
@@ -57,34 +39,4 @@ public class TestUtils {
assertThat(statusCode).isEqualTo(status);
}
public static HashMap<String, Object> parseMultipart(ServerWebExchange exchange, @RequestBody(required = false) String body) {
HashMap<String, Object> files = new HashMap<>();
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
MediaType contentType = headers.getContentType();
String charSet = (contentType.getCharset() == null) ? null : contentType.getCharset().toString();
MultipartContext context = new MultipartContext(contentType.toString(),
(int)headers.getContentLength(), charSet);
AbstractNioMultipartListener listener = new AbstractNioMultipartListener() {
@Override
public void onPartFinished(StreamStorage streamStorage, Map<String, List<String>> headersFromPart) {
String contentDisposition = headersFromPart.get("content-disposition").get(0);
String[] tokens = StringUtils.tokenizeToStringArray(contentDisposition, ";");
String[] nameTokens = StringUtils.tokenizeToStringArray(tokens[1], "=");
String name = StringUtils.deleteAny(nameTokens[1], "\"");
String contentType = headersFromPart.get("content-type").get(0);
ByteArrayInputStream in = (ByteArrayInputStream) streamStorage.getInputStream();
try {
String data = Base64Utils.encodeToString(StreamUtils.copyToByteArray(in));
files.put(name, "data:"+contentType+";base64,"+data);
} catch (IOException e) {
ReflectionUtils.rethrowRuntimeException(e);
}
}
};
NioMultipartParser parser = Multipart.multipart(context).forNIO(listener);
parser.write(body.getBytes(), 0, body.getBytes().length);
return files;
}
}