6

I use Servlet 3 @MultiPartConfig annotation to implement file upload in my application. I need set multipart-config location parameter at the runtime (not hardcode in annotaion parameter). Is there any API for programmatic access to multipart-config of servlet?

Thanks

Vik Gamov
  • 5,446
  • 1
  • 26
  • 46

2 Answers2

5

The @MultiPartConfig is really just a marker interface for the container. When the servlet is initialized the annotation values provided are mapped to it with a proxy object. When the incoming request is a multipart/form-data the parts of the upload are mapped to the request, and the container performs the necessary work based upon the values from the annotation and the parts on the request. There is no way for you to intercept this process since it all happens within the guts of the container. However, there is one alternative. It requires performing a file system operation a second time. Since you have all the parts you can reconstruct the file and "re-upload" it to the location of your choice. It might look something like the method below. Keep in mind although I tested this quickly in a servlet of my own to demonstrate the concept it is obviously not finished code:

@Override
protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
        throws ServletException, IOException {

    httpServletResponse.setContentType("text/html");
    PrintWriter printWriter = httpServletResponse.getWriter();

    InputStream inputStream;
    FileOutputStream fileOutputStream;

    for (Part part : httpServletRequest.getParts()) {

        inputStream = httpServletRequest.getPart(part.getName()).getInputStream();
        int i = inputStream.available();
        byte[] b = new byte[i];
        inputStream.read(b);
        String fileName = "";

        for (String temp : part.getHeader("content-disposition").split(";")) {
            if (temp.trim().startsWith("filename")) {
                fileName = temp.substring(temp.indexOf('=') + 1).trim().replace("\"", "");
            }
        }

        String uploadDir = "/temp";
        fileOutputStream = new FileOutputStream(uploadDir + "/" + fileName);
        fileOutputStream.write(b);
        inputStream.close();
        fileOutputStream.close();

        printWriter.write("Uploaded file " + uploadDir + "/" + fileName + ".");
    }
}
  • If you're using @MultiPartConfig and need a runtime file location then you have no other option than to "re-upload" the parts. –  Feb 09 '14 at 01:36
1

I had your same problem too and the solution is simple: standard Servlet 3.0 file upload is not enough: just grab the jars from Apache FileUpload Commons and you're done

Just look at this crystal clear example with Streaming API

   ServletFileUpload upload = new ServletFileUpload();

   // Parse the request
    FileItemIterator iter = upload.getItemIterator(request);
    while (iter.hasNext()) {
      FileItemStream item = iter.next();
      String name = item.getFieldName();
      InputStream stream = item.openStream();
      if ( item.isFormField() == false) 
          System.out.println("File field " + name + " with file name "
            + item.getName() + " detected."); 
          FileOutputStream fos = new FileOutputStream("your_location"); 
          Streams.copy ( stream,  fos, true);

       }
    }
Nestor Hernandez Loli
  • 1,412
  • 3
  • 21
  • 26
  • The question was about @MultiPartConfig and file upload, which you didn't address. You're also streaming from an item already on the request (uploaded in memory), and that means you're simply reading it "re-uploading" again. –  Feb 09 '14 at 01:31
  • @Brian Reindel that's not the case, I'm not 're-uploading' again, with the Streaming API what I do is a direct parsing of the request with no temporal files or caching in memory. In fact that's the advantage with Streaming API: Memory efficient and faster processing, please check http://commons.apache.org/proper/commons-fileupload/streaming.html – Nestor Hernandez Loli Feb 09 '14 at 01:52
  • Assuming you're in a Servlet, and using a container, how did the file item get on the request? The bytes are already loaded in memory. You're not streaming the contents real time while they are being uploaded. You are correct that the advantage of your approach over FileUpload is because in that case the file first must be written to the file system. I don't disagree that having to manage two files on disk is problematic. However, the question was specifically addressing the @MultiPartConfig annotation and the runtime location of the file, and not simply file upload in general. –  Feb 09 '14 at 03:28
  • I agree with you with : 'However, the question was specifically addressing the @MultiPartConfig annotation and the runtime location of the file, and not simply file upload in general', I just wanted to note that there is a much better way to do things. I disagree with you when you say :'The bytes are already loaded in memory', please check the link to Stream API I posted. – Nestor Hernandez Loli Feb 09 '14 at 04:03
  • Please don't confuse the Commons FileUpload Traditional API with the Streaming API. – Nestor Hernandez Loli Feb 09 '14 at 04:10
  • The Traditional API has the behaviour that you, correctly, mentioned. The Streaming API streams the contents real time while they are being uploaded. – Nestor Hernandez Loli Feb 09 '14 at 05:03
  • Regarding streaming real time, I did not get that from the link you posted. In reviewing the source code and documentation I do not see anything that indicates when used within a servlet that this streams real time. From what I gather the streaming API streams off the request contents from the uploaded file. If you were to put the above code in a doPost() method of a servlet, and examine the request after a file upload (but before hitting ServletFileUpload) you should find that the bytes of the file you uploaded exist in memory on the request. I apologize if I'm misunderstanding. –  Feb 11 '14 at 20:56