通过HTTP PUT请求上传文件

时间:2013-09-10 20:24:02

标签: java rest spring-mvc file-upload put

有没有人知道像Apache Commons FileUpload这样的产品或库会处理PUT文件上传?

非常感谢任何友好的建议或指示!

全文:

我们开始为我们的java webapp实现文件上传休息(如)服务,但似乎没有任何“简单”的解决方案来处理通过HTTP PUT方法上传文件。

我们希望找到像Apache Commons FileUpload项目这样的库,但不仅要处理“基于表单的HTML文件上传”和/或“multipart / form-data”。

我们非常希望FileUpload能够临时存储文件,在询问时移动这些文件,然后在不再使用后清理临时文件。我们还喜欢这样一个事实,即Spring会自动将MultipartFile List绑定到我们的命令对象,并且当它进入我们的其他基于html表单的文件上传控制器时,我们可以使用它。

完整堆栈背景:

  • Spring MVC(3.2.3.RELEASE)
  • Tomcat 7
  • 我们正在尝试遵循分层架构(UI,服务/业务逻辑,持久性)

感谢您的时间!


以下网址是一个示例,显示了从请求的InputStream上传文件的功能。代码完成了工作,但生产质量不高。

https://boplicity.nl/confluence/display/spring/Using+HTTP+PUT+and+Spring+MVC+to+upload+files


我们使用以下curl命令来测试我们的web服务:

curl -v -k -X PUT --data-binary @"c:/java/files/tempfilename.txt" https://localhost:8443/api/file/tempfilename.txt
然后,xwoker给出了以下很好的卷曲示例:

curl -v -X PUT -T "myfile" http://localhost:8080/mytargetfilename

2 个答案:

答案 0 :(得分:7)

很容易让Spring能够正确响应HTTP PUT方法的文件上传请求。

只需覆盖自定义isMultipart()课程中的MultipartResolver方法。

import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.servlet.ServletRequestContext;

import javax.servlet.http.HttpServletRequest;

public class PostAndPutCommonsMultipartResolver extends CommonsMultipartResolver {

    private static final String POST_METHOD = "POST";
    private static final String PUT_METHOD = "PUT";

    @Override
    public boolean isMultipart(HttpServletRequest request) {

        boolean isMultipartRequest = false;

        if (request != null) {

            if (POST_METHOD.equalsIgnoreCase(request.getMethod()) || PUT_METHOD.equalsIgnoreCase(request.getMethod())) {

                isMultipartRequest = FileUploadBase.isMultipartContent(new ServletRequestContext(request));
            }
        }

        return isMultipartRequest;
    }
}

真正重要的是扩展默认MultipartResolver,以便isMultipart()方法对POST或PUT请求返回true。

通常,有两个默认的MultipartResolver实现:CommonsMultipartResolver(与Apache Commons FileUpload一起使用)和StandardServletMultipartResolver(与Servlet 3.0+ Part API一起使用)。

由于我们使用Apache Commons FileUpload,我们扩展了CommonsMultipartResolver类。

MultipartResolver's Javadoc页面上有文档说明如何为您的应用程序正确定义自定义MultipartResolver(重点是我的):

  

没有用于Spring的默认解析器实现   DispatcherServlets ,作为应用程序可能会选择解析它   multipart请求自己。要定义实现,请创建一个bean   在DispatcherServlet的应用程序中使用id“multipartResolver”   上下文。这样的解析器将应用于由此处理的所有请求   DispatcherServlet的。

对于xml配置的应用程序,它将看起来接近以下内容:

<bean id="multipartResolver" class="<package>.<name>.PostAndPutCommonsMultipartResolver"/>

对于注释配置的应用程序,它将看起来接近以下内容:

@Bean(name = "multipartResolver")
public CommonsMultipartResolver createMultipartResolver() {
    return new PostAndPutCommonsMultipartResolver();
}

More information on Annotation configuration of MultipartResolver

答案 1 :(得分:1)

我不知道有任何库满足您的要求。但是如果你不介意做一些编码,我认为创造类似东西的好方法就是编写你自己的

public class FileMessageConverter extends AbstractHttpMessageConverter<File> 

将请求主体转换为tmp目录中的File:

@Override
protected File readInternal(Class<? extends File> clazz, HttpInputMessage inputMessage)
        throws IOException, HttpMessageNotReadableException {

    InputStream inputStream = inputMessage.getBody();
    File tmpFile = File.createTempFile("upload","tmp");
    if (inputStream != null) {
        FileOutputStream outputStream = new FileOutputStream(tmpFile);

        byte[] buffer = new byte[1024];
        int bytesRead;

        while ((bytesRead = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, bytesRead);
        }

        outputStream.flush();

        outputStream.close();
    }
    return tmpFile;
}

在控制器中,您可以使用以下方法定义方法:

@RequestMapping(value="/{fileName}", method = RequestMethod.PUT)
public ResponseEntity uploadFile(@PathVariable(value="fileName") String fileName, @RequestBody File tmpFile) throws IOException {

    // .. process tmpFile, e.g. tmpFile.renameTo(new File(fileName);
    return new ResponseEntity<String>(HttpStatus.CREATED);
}

不要忘记注册FileMessageConverter,例如

@Configuration
@EnableWebMvc
@ComponentScan(basePackages =  {"my.controller.package"})
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new FileMessageConverter());
    }
}

调用上传的curl命令:

curl -v -X PUT -T "myfile" http://localhost:8080/mytargetfilename