Java 通过 HTTP PUT 请求上传文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18728100/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:32:02  来源:igfitidea点击:

File Upload via HTTP PUT Request

javarestspring-mvcfile-uploadput

提问by hooknc

Does anyone have any idea of any products or libraries like Apache Commons FileUpload that will deal with PUT file uploads?

有没有人知道将处理 PUT 文件上传的任何产品或库,如 Apache Commons FileUpload?

Any friendly advice or direction would be very much appreciated!

任何友好的建议或方向将不胜感激!

Full Story:

全文:

We are starting to implement a file upload rest(like) service for our java webapp, but there doesn't seem to be any 'easy' solutions for dealing with file uploads via the HTTP PUT method.

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

We are hoping to find a library like the Apache Commons FileUploadproject, but something that doesn't only deal with "Form-based File Upload in HTML" and/or "multipart/form-data".

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

We really like FileUpload's ability to store files temporarily, move those files when asked, and then clean up the temporary files after they are no longer used. We also like the fact that Spring will automajically bind the MultipartFile List to our command object and its just available for us to use when it gets into our other html form based file upload controllers.

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

Full Stack Background:

全栈背景:

  • Spring MVC (3.2.3.RELEASE)
  • Tomcat 7
  • We are trying to follow a layered architecture (UI, services/business logic, persistence)
  • Spring MVC (3.2.3.RELEASE)
  • 雄猫 7
  • 我们正在尝试遵循分层架构(UI、服务/业务逻辑、持久性)

Thank you for your time!

感谢您的时间!



The following url is an example that shows the ability to upload a file from the request's InputStream. The code gets the work done but it isn't quite production quality.

以下 url 是一个示例,展示了从请求的 InputStream 上传文件的能力。代码完成了工作,但它的生产质量并不高。

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

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



We are using the following curl command to test our webservice:

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

curl -v -k -X PUT --data-binary @"c:/java/files/tempfilename.txt" https://localhost:8443/api/file/tempfilename.txt

xwoker then gave the following nice curl example:

xwoker 然后给出了以下漂亮的 curl 示例:

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

采纳答案by hooknc

It is fairly painless to get spring to respond correctly to a File Upload request for an HTTP PUT Method.

让 spring 正确响应 HTTP PUT 方法的文件上传请求是相当轻松的。

All it takes is overriding the isMultipart()method in a customized MultipartResolverclass.

它所需要的只是覆盖自定义MultipartResolver类中的isMultipart()方法。

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;
    }
}

What is really important, is that the default MultipartResolveris extended so that the isMultipart()method will return a true for either a POST or PUT request.

真正重要的是,默认MultipartResolver已扩展,因此isMultipart()方法将为 POST 或 PUT 请求返回 true。

In general there are two default MultipartResolver implementations: CommonsMultipartResolver(used with Apache Commons FileUpload) and StandardServletMultipartResolver(used with Servlet 3.0+ Part API).

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

Since we are using Apache Commons FileUploadwe extended the CommonsMultipartResolver class.

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

There is documentation on the MultipartResolver's Javadocpage that explains how to properly define a customized MultipartResolver for your application (emphasis added):

MultipartResolver 的 Javadoc页面上的文档解释了如何为您的应用程序正确定义自定义 MultipartResolver(已添加重点):

There is no default resolver implementation used for Spring DispatcherServlets, as an application might choose to parse its multipart requests itself. To define an implementation, create a bean with the id "multipartResolver" in a DispatcherServlet's application context. Such a resolver gets applied to all requests handled by that DispatcherServlet.

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

For an xml configured application it will look close to the following:

对于 xml 配置的应用程序,它将类似于以下内容:

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

For an annotation configured application it will look close to the following:

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

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

More information on Annotation configuration of MultipartResolver.

有关 MultipartResolver 的注释配置的更多信息

回答by xwoker

I'm not aware of any libraries that fulfill your requirements. But if you don't mind to do some coding, I think nice way to create something similar would be to write your own

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

public class FileMessageConverter extends AbstractHttpMessageConverter<File> 

that converts the request body to File in the tmp directory:

将请求正文转换为 tmp 目录中的文件:

@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;
}

In the controller you would define your method with:

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

@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);
}

Don't forget to register your FileMessageConverter, e.g.

不要忘记注册您的 FileMessageConverter,例如

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

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

The curl command to invoke the upload:

调用上传的 curl 命令:

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