diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java index bc870ea5d55..b896470e9c0 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,11 +16,20 @@ package org.springframework.web.bind.support; +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.Part; + import org.springframework.beans.MutablePropertyValues; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; import org.springframework.validation.BindException; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; +import org.springframework.web.multipart.MultipartException; import org.springframework.web.multipart.MultipartRequest; /** @@ -50,6 +59,7 @@ import org.springframework.web.multipart.MultipartRequest; * ... * * @author Juergen Hoeller + * @author Brian Clozel * @since 2.5.2 * @see #bind(org.springframework.web.context.request.WebRequest) * @see #registerCustomEditor @@ -59,6 +69,7 @@ import org.springframework.web.multipart.MultipartRequest; */ public class WebRequestDataBinder extends WebDataBinder { + /** * Create a new WebRequestDataBinder instance, with default object name. * @param target the target object to bind onto (or {@code null} @@ -89,22 +100,27 @@ public class WebRequestDataBinder extends WebDataBinder { *
Multipart files are bound via their parameter name, just like normal * HTTP parameters: i.e. "uploadedFile" to an "uploadedFile" bean property, * invoking a "setUploadedFile" setter method. - *
The type of the target property for a multipart file can be MultipartFile, + *
The type of the target property for a multipart file can be Part, MultipartFile,
* byte[], or String. The latter two receive the contents of the uploaded file;
* all metadata like original file name, content type, etc are lost in those cases.
* @param request request with parameters to bind (can be multipart)
* @see org.springframework.web.multipart.MultipartRequest
* @see org.springframework.web.multipart.MultipartFile
- * @see #bindMultipartFiles
+ * @see javax.servlet.http.Part
* @see #bind(org.springframework.beans.PropertyValues)
*/
public void bind(WebRequest request) {
MutablePropertyValues mpvs = new MutablePropertyValues(request.getParameterMap());
- if (request instanceof NativeWebRequest) {
+
+ if(isMultipartRequest(request) && (request instanceof NativeWebRequest)) {
MultipartRequest multipartRequest = ((NativeWebRequest) request).getNativeRequest(MultipartRequest.class);
if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
+ else if (ClassUtils.hasMethod(HttpServletRequest.class, "getParts")) {
+ HttpServletRequest serlvetRequest = ((NativeWebRequest) request).getNativeRequest(HttpServletRequest.class);
+ new Servlet3MultipartHelper().bindParts(serlvetRequest, mpvs);
+ }
}
doBind(mpvs);
}
@@ -121,4 +137,37 @@ public class WebRequestDataBinder extends WebDataBinder {
}
}
+ /**
+ * Check if the request is a multipart request (by checking its Content-Type header).
+ *
+ * @param request request with parameters to bind
+ */
+ private boolean isMultipartRequest(WebRequest request) {
+ String contentType = request.getHeader("Content-Type");
+ return ((contentType != null) && StringUtils.startsWithIgnoreCase(contentType, "multipart"));
+ }
+
+
+ /**
+ * Encapsulate Part binding code for Servlet 3.0+ only containers.
+ * @see javax.servlet.http.Part
+ */
+ private static class Servlet3MultipartHelper {
+
+ public void bindParts(HttpServletRequest request, MutablePropertyValues mpvs) {
+ try {
+ for(Part part : request.getParts()) {
+ mpvs.add(part.getName(), part);
+ }
+ }
+ catch (IOException ex) {
+ throw new MultipartException("Failed to get request parts", ex);
+ }
+ catch(ServletException ex) {
+ throw new MultipartException("Failed to get request parts", ex);
+ }
+ }
+
+ }
+
}
diff --git a/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderIntegrationTests.java b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderIntegrationTests.java
new file mode 100644
index 00000000000..66e91dda57b
--- /dev/null
+++ b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderIntegrationTests.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2002-2013 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.bind.support;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.Part;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.mock.web.test.MockMultipartFile;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.SocketUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.context.request.ServletWebRequest;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * @author Brian Clozel
+ */
+public class WebRequestDataBinderIntegrationTests {
+
+ protected static String baseUrl;
+
+ protected static MediaType contentType;
+
+ private static Server jettyServer;
+
+ private RestTemplate template;
+
+ private static PartsServlet partsServlet;
+
+ private static PartListServlet partListServlet;
+
+
+ @Before
+ public void createTemplate() {
+ template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
+ }
+
+ @BeforeClass
+ public static void startJettyServer() throws Exception {
+ int port = SocketUtils.findAvailableTcpPort();
+ jettyServer = new Server(port);
+ baseUrl = "http://localhost:" + port;
+ ServletContextHandler handler = new ServletContextHandler();
+
+ partsServlet = new PartsServlet();
+ partListServlet = new PartListServlet();
+
+ handler.addServlet(new ServletHolder(partsServlet), "/parts");
+ handler.addServlet(new ServletHolder(partListServlet), "/partlist");
+ jettyServer.setHandler(handler);
+ jettyServer.start();
+ }
+
+ @AfterClass
+ public static void stopJettyServer() throws Exception {
+ if (jettyServer != null) {
+ jettyServer.stop();
+ }
+ }
+
+
+ @Test
+ public void testPartsBinding() {
+
+ PartsBean bean = new PartsBean();
+ partsServlet.setBean(bean);
+
+ MultiValueMap