Multipart File upload Spring Boot
Im using Spring Boot and want to use a Controller to receive a multipart file upload. When sending the file I keep getting the error 415 unsupported content type response and the controller is never reached
There was an unexpected error (type=Unsupported Media Type, status=415).
Content type 'multipart/form-data;boundary=----WebKitFormBoundary1KvzQ1rt2V1BBbb8' not supported
Ive tried sending using form:action in html/jsp page and also in a standalone client application which uses RestTemplate. All attempts give the same result
multipart/form-data;boundary=XXXXX not supported.
It seems from multipart documentation that the boundary param has to be added to the multipart upload however this seems to not match the controller receiving "multipart/form-data"
My controller method is setup as follows
@RequestMapping(value = "/things", method = RequestMethod.POST, consumes = "multipart/form-data" ,
produces = { "application/json", "application/xml" })
public ResponseEntity<ThingRepresentation> submitThing(HttpServletRequest request,
@PathVariable("domain") String domainParam,
@RequestParam(value = "type") String thingTypeParam,
@RequestBody MultipartFile[] submissions) throws Exception
With Bean Setup
@Bean
public MultipartConfigElement multipartConfigElement() {
return new MultipartConfigElement("");
}
@Bean
public MultipartResolver multipartResolver() {
org.springframework.web.multipart.commons.CommonsMultipartResolver multipartResolver = new org.springframework.web.multipart.commons.CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(1000000);
return multipartResolver;
}
As you can see I've set the consumes type to "multipart/form-data" but when the multipart is sent it must have a boundary parameter and places a random boundary string.
Can anyone please tell me how I can either set the content type in controller to match or change my request to match my controller setup?
My attempts to send ... Attempt 1...
<html lang="en">
<body>
<br>
<h2>Upload New File to this Bucket</h2>
<form action="http://localhost:8280/appname/domains/abc/things?type=abcdef00-1111-4b38-8026-315b13dc8706" method="post" enctype="multipart/form-data">
<table width="60%" border="1" cellspacing="0">
<tr>
<td width="35%"><strong>File to upload</strong></td>
<td width="65%"><input type="file" name="file" /></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" name="submit" value="Add" /></td>
</tr>
</table>
</form>
</body>
</html>
Attempt 2....
RestTemplate template = new RestTemplate();
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("file", new FileSystemResource(pathToFile));
try{
URI response = template.postForLocation(url, parts);
}catch(HttpClientErrorException e){
System.out.println(e.getResponseBodyAsString());
}
Attempt 3...
FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
formHttpMessageConverter.setCharset(Charset.forName("UTF8"));
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add( formHttpMessageConverter );
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("file", new FileSystemResource(path));
HttpHeaders imageHeaders = new HttpHeaders();
imageHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> imageEntity = new HttpEntity<MultiValueMap<String, Object>>(map, imageHeaders);
ResponseEntity e= restTemplate.exchange(uri, HttpMethod.POST, imageEntity, Boolean.class);
System.out.println(e.toString());
@RequestBody MultipartFile[] submissions
should be
@RequestParam("file") MultipartFile[] submissions
The files are not the request body, they are part of it and there is no built-in HttpMessageConverter
that can convert the request to an array of MultiPartFile
.
You can also replace HttpServletRequest
with MultipartHttpServletRequest
, which gives you access to the headers of the individual parts.
You can simply use a controller method like this:
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<?> uploadFile(
@RequestParam("file") MultipartFile file) {
try {
// Handle the received file here
// ...
}
catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.OK);
} // method uploadFile
Without any additional configurations for Spring Boot.
Using the following html form client side:
<html>
<body>
<form action="/uploadFile" method="POST" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
</body>
</html>
If you want to set limits on files size you can do it in the application.properties
:
# File size limit
multipart.maxFileSize = 3Mb
# Total request size for a multipart/form-data
multipart.maxRequestSize = 20Mb
Moreover to send the file with Ajax take a look here: http://blog.netgloo.com/2015/02/08/spring-boot-file-upload-with-ajax/
Latest version of SpringBoot makes uploading multiple files very easy also. On the browser side you just need the standard HTML upload form, but with multiple input elements (one per file to upload, which is very important), all having the same element name (name="files" for the example below)
Then in your Spring @Controller class on the server all you need is something like this:
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody ResponseEntity<?> upload(
@RequestParam("files") MultipartFile[] uploadFiles) throws Exception
{
...now loop over all uploadFiles in the array and do what you want
return new ResponseEntity<>(HttpStatus.OK);
}
Those are the tricky parts. That is, knowing to create multiple input elements each named "files", and knowing to use a MultipartFile[] (array) as the request parameter are the tricky things to know, but it's just that simple. I won't get into how to process a MultipartFile entry, because there's plenty of docs on that already.
@Bean
MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setMaxFileSize("5120MB");
factory.setMaxRequestSize("5120MB");
return factory.createMultipartConfig();
}
put it in class where you are defining beans
In Controller, your method should be;
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public ResponseEntity<SaveResponse> uploadAttachment(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
....
Further, you need to update application.yml (or application.properties) to support maximum file size and request size.
spring:
http:
multipart:
max-file-size: 5MB
max-request-size: 20MB