I am trying to post of List of MultipartFile to my RestController using spring restTemplate although I'm a bit confused as to the exact syntax & types to use for my client & controller. Here's what I have so far based on the research I've done...
FileUploadClient.java
public void uploadFiles(List<MultipartFile> multiPartFileList) throws IOException {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
List<Object> files = new ArrayList<>();
for(MultipartFile file : multiPartFileList) {
files.add(new ByteArrayResource(file.getBytes()));
}
map.put("files", files);
// headers is inherited from BaseClient
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(map, headers);
ResponseEntity<String> response = restTemplate.exchange(restURI + "/rest/fileupload/uploadfiles", HttpMethod.POST, request, String.class);
if(HttpStatus.OK.equals(response.getStatusCode())) {
System.out.println("status for /rest/fileupload/uploadfiles ---> " + response);
}
}
FileUploadRestController.java
@RequestMapping(value = "/uploadfiles", method = RequestMethod.POST)
public ResponseEntity<?> uploadFiles(@RequestParam("files") List<MultipartFile> files, HttpServletRequest request) {
ResponseEntity<?> response;
try {
// do stuff...
response = new ResponseEntity<>(header, HttpStatus.OK);
System.out.println("file uploaded");
} catch (Exception e) {
// handle exception
}
return response;
}
web.xml
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
spring-servlet.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- max upload size in bytes -->
<property name="maxUploadSize" value="20971520" /> <!-- 20MB -->
<!-- max size of file in memory (in bytes) -->
<property name="maxInMemorySize" value="1048576" /> <!-- 1MB -->
</bean>
If I understand it correctly. The multipart filter should parse my MultiValueMap into a List of MultipartFiles and a MultipartHttpServletRequest? The only way I can get my client to hit my RestController is to send the file data as a ByteArrayResource, however in my Controller my RequestBody is always null and the MultipartHttpServletRequest has an empty map for its multipartFiles attribute. I've looked at numerous posts to try to resolve this issue but to no avail. Any help would be much appreciated.
It looks like the request
payload that you are sending from FileUploadClient
does not match what's server is expecting. Could you try changing the following:
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
for(MultipartFile file : multiPartFileList) {
map.add(file.getName(), new ByteArrayResource(file.getBytes()));
}
to
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
List<ByteArrayResource> files = new ArrayList<>();
for(MultipartFile file : multiPartFileList) {
files.add(new ByteArrayResource(file.getBytes()));
}
map.put("files", files);
Also, could you try changing the server's method signature to the following:
public ResponseEntity<?> uploadFiles(@RequestParam("files") List<MultipartFile> files, HttpServletRequest request) {
Update
While uploading multiple files, you need to make sure getFileName
of ByteArrayResource
returns same value every time. If not, you will always get an empty array.
E.g. the following works for me:
Client:
MultiValueMap<String, Object> data = new LinkedMultiValueMap<String, Object>();
for(MultipartFile file : multiPartFileList) {
ByteArrayResource resource = new ByteArrayResource(file.getBytes()) {
@Override
public String getFilename() {
return "";
}
};
data.add("files", resource);
}
Server
public ResponseEntity<?> upload(@RequestParam("files") MultipartFile[] files){