Add ServerRequest::multipartData in WebMvc.fn

This commit adds the multipartData method to ServerRequest in WebMvc.fn,
returning a MultiValueMap<String, Part>.

Closes gh-24909
This commit is contained in:
Arjen Poutsma
2020-04-20 16:54:56 +02:00
parent 60725294e2
commit 54e6103def
5 changed files with 72 additions and 1 deletions

View File

@@ -44,6 +44,7 @@ import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
@@ -85,6 +86,9 @@ class DefaultServerRequest implements ServerRequest {
private final Map<String, Object> attributes;
@Nullable
private MultiValueMap<String, Part> parts;
public DefaultServerRequest(HttpServletRequest servletRequest, List<HttpMessageConverter<?>> messageConverters) {
this.serverHttpRequest = new ServletServerHttpRequest(servletRequest);
@@ -228,6 +232,19 @@ class DefaultServerRequest implements ServerRequest {
return this.params;
}
@Override
public MultiValueMap<String, Part> multipartData() throws IOException, ServletException {
MultiValueMap<String, Part> result = this.parts;
if (result == null) {
result = servletRequest().getParts().stream()
.collect(Collectors.groupingBy(Part::getName,
LinkedMultiValueMap::new,
Collectors.toList()));
this.parts = result;
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public Map<String, String> pathVariables() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -30,6 +30,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
@@ -37,6 +38,7 @@ import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
@@ -199,6 +201,14 @@ class DefaultServerRequestBuilder implements ServerRequest.Builder {
return this.methodName;
}
@Override
public MultiValueMap<String, Part> multipartData() throws IOException, ServletException {
return servletRequest().getParts().stream()
.collect(Collectors.groupingBy(Part::getName,
LinkedMultiValueMap::new,
Collectors.toList()));
}
@Override
public URI uri() {
return this.uri;

View File

@@ -40,6 +40,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -994,6 +995,16 @@ public abstract class RequestPredicates {
return this.request.params();
}
@Override
public MultiValueMap<String, Part> multipartData() throws IOException, ServletException {
return this.request.multipartData();
}
@Override
public String pathVariable(String name) {
return this.request.pathVariable(name);
}
@Override
@SuppressWarnings("unchecked")
public Map<String, String> pathVariables() {

View File

@@ -33,6 +33,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.buffer.DataBuffer;
@@ -186,6 +187,17 @@ public interface ServerRequest {
*/
MultiValueMap<String, String> params();
/**
* Get the parts of a multipart request, provided the Content-Type is
* {@code "multipart/form-data"}, or an exception otherwise.
* @return the multipart data, mapping from name to part(s)
* @throws IOException if an I/O error occurred during the retrieval
* @throws ServletException if this request is not of type {@code "multipart/form-data"}
* @since 5.3
* @see HttpServletRequest#getParts()
*/
MultiValueMap<String, Part> multipartData() throws IOException, ServletException;
/**
* Get the path variable with the given name, if present.
* @param name the variable name

View File

@@ -33,6 +33,7 @@ import java.util.Optional;
import java.util.OptionalLong;
import javax.servlet.http.Cookie;
import javax.servlet.http.Part;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -53,6 +54,7 @@ import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.testfixture.server.MockServerWebExchange;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpSession;
import org.springframework.web.testfixture.servlet.MockPart;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
@@ -129,6 +131,25 @@ public class DefaultServerRequestTests {
assertThat(request.param("foo")).isEqualTo(Optional.of("bar"));
}
@Test
public void multipartData() throws Exception {
MockPart formPart = new MockPart("form", "foo".getBytes(UTF_8));
MockPart filePart = new MockPart("file", "foo.txt", "foo".getBytes(UTF_8));
MockHttpServletRequest servletRequest = new MockHttpServletRequest("POST", "/");
servletRequest.addPart(formPart);
servletRequest.addPart(filePart);
DefaultServerRequest request =
new DefaultServerRequest(servletRequest, this.messageConverters);
MultiValueMap<String, Part> result = request.multipartData();
assertThat(result).hasSize(2);
assertThat(result.get("form")).containsExactly(formPart);
assertThat(result.get("file")).containsExactly(filePart);
}
@Test
public void emptyQueryParam() {
MockHttpServletRequest servletRequest = new MockHttpServletRequest("GET", "/");