File Upload via HTTP PUT Request

爷,独闯天下 提交于 2019-11-30 10:01:06

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

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

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 MultipartResolver is extended so that the isMultipart() method will return a true for either a POST or PUT request.

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

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

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

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.

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

<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.

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:

@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.

@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 -v -X PUT -T "myfile" http://localhost:8080/mytargetfilename
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!