File upload of CommonsMultipartFile using RestTemplate is failing

核能气质少年 提交于 2020-01-06 04:35:11

问题


I'm trying to consume a web service that accepts a CommonsMultipartFile in the request. So, I created an HTTP client using Spring's RestTemplate. Below is the method that takes in URI and a MultipartFile as parameters. I'm trying to pass this file to the web service in the form of ByteArrayResource.

public String upload(String uri, MultipartFile file) throws IOException {
    logger.info("URI: " + uri);

    ByteArrayResource fileAsResource = new ByteArrayResource(file.getBytes()) {
        @Override
        public String getFilename() {
            return file.getOriginalFilename();
        }
    };

    MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
    parts.add("file", fileAsResource);
    parts.add("fileName", file.getOriginalFilename());

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);

    HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(parts, httpHeaders);

    ResponseEntity<String> responseEntity = rest.exchange(uri, HttpMethod.POST, requestEntity, String.class);

    this.setStatus(responseEntity.getStatusCode());
    return responseEntity.getBody();
}

This is how I'm creating a CommonsMultipartFile:

private MultipartFile getCommonsMultipartFile() throws FileNotFoundException, IOException {
    File file = new File("C:\\Dummy_Test.txt");

    DiskFileItemFactory factory = new DiskFileItemFactory();
    FileItem fileItem = factory.createItem( "file", "multipart/form-data", false, "Dummy_Test.txt" );
    IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());
    MultipartFile commonsMultipartFile = new CommonsMultipartFile(fileItem);

    return commonsMultipartFile;
}

But whenever I run this client to hit the web service I keep getting this error.

 org.springframework.web.client.ResourceAccessException: I/O error: resource loaded from byte array cannot be resolved to absolute file path; nested exception is java.io.FileNotFoundException: resource loaded from byte array cannot be resolved to absolute file path
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377)
    at com.attikala.service.UploaderService.upload(UploaderService.java:118)
    at com.attikala.service.UploaderService.main(UploaderService.java:55)
Caused by: java.io.FileNotFoundException: resource loaded from byte array cannot be resolved to absolute file path
    at org.springframework.core.io.AbstractResource.getFile(AbstractResource.java:107)
    at org.springframework.core.io.AbstractResource.contentLength(AbstractResource.java:116)
    at org.springframework.http.converter.ResourceHttpMessageConverter.getContentLength(ResourceHttpMessageConverter.java:99)
    at org.springframework.http.converter.ResourceHttpMessageConverter.write(ResourceHttpMessageConverter.java:81)
    at org.springframework.http.converter.ResourceHttpMessageConverter.write(ResourceHttpMessageConverter.java:1)
    at org.springframework.http.converter.FormHttpMessageConverter.writePart(FormHttpMessageConverter.java:288)
    at org.springframework.http.converter.FormHttpMessageConverter.writeParts(FormHttpMessageConverter.java:252)
    at org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:242)
    at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:194)
    at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:1)
    at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:588)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:436)
    ... 4 more

Can someone help me in figuring out what's happening here?

Note: If I use the below code to upload the file, it works perfectly fine.

public String upload(String uri) {
    LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();

    FileSystemResource value = new FileSystemResource(new File("C:\\Dummy_Test.txt"));
    map.add("file", value);
    map.add("fileName", "Dummy_Test.txt");

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.MULTIPART_FORM_DATA);

    HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, String.class);

    return responseEntity.getBody();
}

So, I'm thinking, do I need to provide absolute path always for the file I'm uploading? I know I'm missing something here. Don't know what.

Thanks.


回答1:


Finally, I found what's happening. Here I go -

when this statement

ResponseEntity<String> responseEntity = rest.exchange(uri, HttpMethod.POST, requestEntity, String.class);

gets executed, behind the scenes it's trying to extract the file of type java.io.File from the MultipartFile passed, and then get the file length. But MultipartFile is not of that type and as a result it was throwing an exception.

To fix that I had to also override contentLength() method when creating an instance of ByteArrayResource. Ta-da!

    ByteArrayResource fileAsResource = new ByteArrayResource(file.getBytes()) {

        @Override
        public String getFilename() {
            return file.getOriginalFilename();
        }

        @Override
        public long contentLength() throws IOException {
            return file.getSize();
        }
    };

Hope this helps if anyone runs into the same problem.



来源:https://stackoverflow.com/questions/49738896/file-upload-of-commonsmultipartfile-using-resttemplate-is-failing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!