Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I receive a file upload in spring mvc using both multipart/form and chunked encoding?

I am trying to write a spring mvc method that can receive either a multipart/form or transfer-encoding chunked file upload. I can write a separate method to handle each type but I'd like to do it with the same method so i can use the same REST POST uri such as:

http://host:8084/attachments/testupload 

Here is my best attempt so far:

@RequestMapping(value = { "/testupload" }, method = RequestMethod.POST, produces =    "application/json") public @ResponseBody ResponseEntity<MessageResponseModel> testUpload(   @RequestParam(value = "filedata", required = false) MultipartFile filedata,   final HttpServletRequest request) throws IOException {    InputStream is = null;   if (filedata == null) {     is = request.getInputStream();   }   else {     is = filedata.getInputStream();   }   byte[] bytes = IOUtils.toByteArray(is);   System.out.println("read " + bytes.length + " bytes.");    return new ResponseEntity<MessageResponseModel>(null, null, HttpStatus.OK); } 

Using the above method I can upload a multipart file, but if i upload a chunked file I get an exception from spring that says:

org.springframework.web.multipart.MultipartException: \ The current request is not a multipart request 

If I remove the MultipartFile request param it works great for transfer encoding chunked. If I leave it in it works great for MultipartFile uploads. How can I do it with the same method to handle both upload types?

This works fine for chunked:

@RequestMapping(value = { "/testupload" }, method = RequestMethod.POST, produces =    "application/json") public @ResponseBody ResponseEntity<MessageResponseModel> testUpload(   final HttpServletRequest request) throws IOException {    InputStream is = null;   is = request.getInputStream();   byte[] bytes = IOUtils.toByteArray(is);   System.out.println("read " + bytes.length + " bytes.");    return new ResponseEntity<MessageResponseModel>(null, null, HttpStatus.OK); } 

and this works great for MultipartFile:

@RequestMapping(value = { "/testupload" }, method = RequestMethod.POST, produces =    "application/json") public @ResponseBody ResponseEntity<MessageResponseModel> testUpload(   @RequestParam MultipartFile filedata) throws IOException {    InputStream is = null;   is = filedata.getInputStream();   byte[] bytes = IOUtils.toByteArray(is);   System.out.println("read " + bytes.length + " bytes.");    return new ResponseEntity<MessageResponseModel>(null, null, HttpStatus.OK); } 

It should be possible, does anybody know how to do this?

Thank you, Steve

like image 329
Steve L Avatar asked Nov 23 '13 12:11

Steve L


People also ask

How would you handle the situation where a user uploads a very large file through a form in your Spring MVC application?

A new attribute "maxSwallowSize" is the key to deal this situation. It should happen when you upload a file which is larger than 2M. Because the 2M is the default value of this new attribute .

Which dependency is needed to support uploading a file in MVC?

The dependency needed for MVC is the spring-webmvc package. The javax. validation and the hibernate-validator packages will be also used here for validation. The commons-io and commons-fileupload packages are used for uploading the file.

How does multipart file upload work?

Multipart upload allows you to upload a single object as a set of parts. Each part is a contiguous portion of the object's data. You can upload these object parts independently and in any order. If transmission of any part fails, you can retransmit that part without affecting other parts.


2 Answers

Excerpt from my code (Spring 3.2, blueimp file upload with AngularJS):

/**  * Handles chunked file upload, when file exceeds defined chunked size.  *   * This method is also called by modern browsers and IE >= 10  */ @RequestMapping(value = "/content-files/upload/", method = RequestMethod.POST, headers = "content-type!=multipart/form-data") @ResponseBody public UploadedFile uploadChunked(         final HttpServletRequest request,         final HttpServletResponse response) {      request.getHeader("content-range");//Content-Range:bytes 737280-819199/845769     request.getHeader("content-length"); //845769     request.getHeader("content-disposition"); // Content-Disposition:attachment; filename="Screenshot%20from%202012-12-19%2017:28:01.png"     request.getInputStream(); //actual content.      //Regex for content range: Pattern.compile("bytes ([0-9]+)-([0-9]+)/([0-9]+)");     //Regex for filename: Pattern.compile("(?<=filename=\").*?(?=\")");      //return whatever you want to json     return new UploadedFile(); }  /**  * Default Multipart file upload. This method should be invoked only by those that do not  * support chunked upload.  *   * If browser supports chunked upload, and file is smaller than chunk, it will invoke  * uploadChunked() method instead.  *   * This is instead a fallback method for IE <=9  */ @RequestMapping(value = "/content-files/upload/", method = RequestMethod.POST, headers = "content-type=multipart/form-data") @ResponseBody public HttpEntity<UploadedFile> uploadMultipart(         final HttpServletRequest request,         final HttpServletResponse response,         @RequestParam("file") final MultipartFile multiPart) {      //handle regular MultipartFile      // IE <=9 offers to save file, if it is returned as json, so set content type to plain.     HttpHeaders headers = new HttpHeaders();     headers.setContentType(MediaType.TEXT_PLAIN);     return new HttpEntity<>(new UploadedFile(), headers); } 

This should get you started. Minimal testing done on IE8, IE9, IE10, Chrome, FF. Of course there might be issues, and probably there is an easier way of extracting content ranges, but .. works for me.

like image 190
gerasalus Avatar answered Sep 22 '22 01:09

gerasalus


Here is the controller for that

package com.faisalbhagat.web.controller;  @Controller @RequestMapping(value = { "" }) public class UploadController {      @RequestMapping(value = "/uploadMyFile", method = RequestMethod.POST)     @ResponseBody     public String handleFileUpload(MultipartHttpServletRequest request)             throws Exception {         Iterator<String> itrator = request.getFileNames();         MultipartFile multiFile = request.getFile(itrator.next());                 try {             // just to show that we have actually received the file             System.out.println("File Length:" + multiFile.getBytes().length);             System.out.println("File Type:" + multiFile.getContentType());             String fileName=multiFile.getOriginalFilename();             System.out.println("File Name:" +fileName);             String path=request.getServletContext().getRealPath("/");              //making directories for our required path.             byte[] bytes = multiFile.getBytes();             File directory=    new File(path+ "/uploads");             directory.mkdirs();             // saving the file             File file=new File(directory.getAbsolutePath()+System.getProperty("file.separator")+picture.getName());             BufferedOutputStream stream = new BufferedOutputStream(                     new FileOutputStream(file));             stream.write(bytes);             stream.close();         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();             throw new Exception("Error while loading the file");         }         return toJson("File Uploaded successfully.")     }      public String toJson(Object data)     {         ObjectMapper mapper=new ObjectMapper();         StringBuilder builder=new StringBuilder();         try {             builder.append(mapper.writeValueAsString(data));         } catch (Exception e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         return builder.toString();     } } 

you can find comple solution at with client side code at http://faisalbhagat.blogspot.com/2014/09/springmvc-fileupload-with-ajax-and.html

like image 41
faisalbhagat Avatar answered Sep 23 '22 01:09

faisalbhagat