From 741aff1393965907fbca1d0201e204cc33ce68ca Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 2 Oct 2009 22:24:09 +0000 Subject: [PATCH] INT-749 initial commit of file upload support --- .../http/DefaultInboundRequestMapper.java | 30 +++++- .../DefaultInboundRequestMapperTests.java | 30 ++++++ .../integration/http/StubMultipartFile.java | 94 +++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 org.springframework.integration.http/src/test/java/org/springframework/integration/http/StubMultipartFile.java diff --git a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java index 7b438065b1..1469a5b467 100644 --- a/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java +++ b/org.springframework.integration.http/src/main/java/org/springframework/integration/http/DefaultInboundRequestMapper.java @@ -17,6 +17,7 @@ package org.springframework.integration.http; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -76,7 +77,9 @@ public class DefaultInboundRequestMapper implements InboundRequestMapper { private volatile MultipartResolver multipartResolver; - private String multipartCharset = null; + private volatile String multipartCharset = null; + + private volatile boolean copyUploadedFiles; /** @@ -96,6 +99,17 @@ public class DefaultInboundRequestMapper implements InboundRequestMapper { this.multipartCharset = multipartCharset; } + /** + * Specify whether uploaded multipart files should be copied to a temporary + * file on the server. If this is set to 'true', the payload map will + * contain a File instance as the value for each multipart file entry. + * Otherwise the uploaded file's content will be converted to either a + * String or byte array based on the content-type (String for "text/*" and + * byte array otherwise). The default value is false. + */ + public void setCopyUploadedFiles(boolean copyUploadedFiles) { + this.copyUploadedFiles = copyUploadedFiles; + } public Message toMessage(HttpServletRequest request) throws Exception { try { @@ -185,8 +199,20 @@ public class DefaultInboundRequestMapper implements InboundRequestMapper { Map fileMap = (Map) multipartRequest.getFileMap(); for (Map.Entry entry : fileMap.entrySet()) { MultipartFile multipartFile = entry.getValue(); + if (multipartFile.isEmpty()) { + continue; + } try { - if (multipartFile.getContentType() != null && multipartFile.getContentType().startsWith("text")) { + if (this.copyUploadedFiles) { + File tmpFile = File.createTempFile("si_", null); + multipartFile.transferTo(tmpFile); + payloadMap.put(entry.getKey(), tmpFile); + if (logger.isDebugEnabled()) { + logger.debug("copied uploaded file [" + multipartFile.getOriginalFilename() + + "] to temporary file [" + tmpFile.getAbsolutePath() + "]"); + } + } + else if (multipartFile.getContentType() != null && multipartFile.getContentType().startsWith("text")) { String multipartFileAsString = this.multipartCharset != null ? new String(multipartFile.getBytes(), this.multipartCharset) : new String(multipartFile.getBytes()); diff --git a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java index 3fe184c8ca..3b277e5c1b 100644 --- a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java +++ b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/DefaultInboundRequestMapperTests.java @@ -18,9 +18,22 @@ package org.springframework.integration.http; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.util.HashMap; +import java.util.Map; + import org.junit.Test; + import org.springframework.integration.core.Message; import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest; /** * @author Iwein Fuld @@ -81,4 +94,21 @@ public class DefaultInboundRequestMapperTests { assertThat(message.getPayload(), is(content)); } + @Test + public void multipartUpload() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + MultiValueMap files = new LinkedMultiValueMap(); + MultipartFile file = new StubMultipartFile("file", "testFile.txt", "foo"); + files.add("file", file); + Map params = new HashMap(); + MultipartHttpServletRequest multipartRequest = new DefaultMultipartHttpServletRequest(request, files, params); + mapper.setCopyUploadedFiles(true); + Message result = mapper.toMessage(multipartRequest); + File tmpFile = (File) ((Map) result.getPayload()).get("file"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + FileCopyUtils.copy(new FileInputStream(tmpFile), baos); + assertThat(baos.toString(), is("foo")); + tmpFile.deleteOnExit(); + } + } diff --git a/org.springframework.integration.http/src/test/java/org/springframework/integration/http/StubMultipartFile.java b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/StubMultipartFile.java new file mode 100644 index 0000000000..1772f367aa --- /dev/null +++ b/org.springframework.integration.http/src/test/java/org/springframework/integration/http/StubMultipartFile.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2009 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.integration.http; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.springframework.web.multipart.MultipartFile; + +/** + * @author Mark Fisher + */ +public class StubMultipartFile implements MultipartFile { + + private final String parameterName; + + private final String filename; + + private final byte[] bytes; + + private final String text; + + + public StubMultipartFile(String parameterName, String filename, String text) { + this.parameterName = parameterName; + this.filename = filename; + if (text != null) { + this.bytes = text.getBytes(); + } + else { + this.bytes = null; + } + this.text = text; + } + + public StubMultipartFile(String parameterName, String filename, byte[] bytes) { + this.parameterName = parameterName; + this.filename = filename; + this.bytes = bytes; + this.text = null; + } + + public byte[] getBytes() throws IOException { + return this.bytes; + } + + public String getContentType() { + return (this.text != null) ? "text" : null; + } + + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(this.bytes); + } + + public String getName() { + return this.parameterName; + } + + public String getOriginalFilename() { + return this.filename; + } + + public long getSize() { + return this.bytes.length; + } + + public boolean isEmpty() { + return this.bytes == null || this.bytes.length == 0; + } + + public void transferTo(File dest) throws IOException, IllegalStateException { + FileOutputStream fos = new FileOutputStream(dest); + fos.write(this.bytes); + fos.close(); + } + +}