Organizational Research By

Surprising Reserch Topic

How to upload files to server using JSP/Servlet?



asked May 21, 2015 in JSP by rajesh
0 votes
122 views



Related Hot Questions

1 Answer

0 votes
 
Best answer
Introduction

To browse and select a file for upload you need a HTML field in the form. As stated in the HTML specification you have to use the POST method and the enctype attribute of the form has to be set to "multipart/form-data".


    
    
    

After submitting such a form, the binary multipart form data is available in the request body in a different format than when the enctype isn't set.

Before Servlet 3.0, the Servlet API didn't natively support multipart/form-data. It supports only the default form enctype of application/x-www-form-urlencoded. The request.getParameter() and consorts would all return null when using multipart form data.

Don't manually parse it!

You can in theory parse the request body yourself based on ServletRequest#getInputStream(). However, this is a precise and tedious work which requires precise knowledge of RFC2388. You shouldn't try to do this on your own or copypaste some homegrown library-less code found elsewhere on the Internet. Many online sources have failed hard in this, such as roseindia.net. See also uploading of pdf file. You should rather use a real library which is used (and implicitly tested!) by millions of users for years. Such a library has proven its robustness.

When you're not on Servlet 3.0 yet, use Apache Commons FileUpload

If you're not on Servlet 3.0 yet, the common practice is to make use of Apache Commons FileUpload to parse the multpart form data requests. It has an excellent User Guide and FAQ (carefully go through both). There's also the O'Reilly ("cos") MultipartRequest, but it has some (minor) bugs and isn't actively maintained anymore for years. I wouldn't recommend using it. Apache Commons FileUpload is still actively maintained and currently very mature.

In order to use Apache Commons FileUpload, you need to have at least the following files in your webapp's /WEB-INF/lib:

commons-fileupload.jar
commons-io.jar
Your initial attempt failed most likely because you forgot the commons IO.

Here's a kickoff example how the doPost() of your UploadServlet may look like when using Apache Commons FileUpload:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        List items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
        for (FileItem item : items) {
            if (item.isFormField()) {
                // Process regular form field (input type="text|radio|checkbox|etc", select, etc).
                String fieldName = item.getFieldName();
                String fieldValue = item.getString();
                // ... (do your job here)
            } else {
                // Process form file field (input type="file").
                String fieldName = item.getFieldName();
                String fileName = FilenameUtils.getName(item.getName());
                InputStream fileContent = item.getInputStream();
                // ... (do your job here)
            }
        }
    } catch (FileUploadException e) {
        throw new ServletException("Cannot parse multipart request.", e);
    }

    // ...
}
Alternatively you can also wrap this all in a Filter which parses it all automagically and put the stuff back in the parametermap of the request so that you can continue using request.getParameter() the usual way and retrieve the uploaded file by request.getAttribute(). You can find an example in this blog article.

When you're already on Servlet 3.0 or newer, use native API

If you're already on the fresh new Servlet 3.0 API, then you can just use standard API provided HttpServletRequest#getPart() to collect the individual multipart form data items (most Servlet 3.0 implementations actually use Apache Commons FileUpload under the covers for this!). This is a bit less convenienced than when using pure Apache Commons FileUpload (a custom utility method is needed to get the filename, this is fixed in Servlet 3.1, see later), but it is workable and easier to use if you already know the input field names beforehand like as you would do with getParameter(). Also, normal form fields are since Servlet 3.0 available by getParameter() the usual way.

First annotate your servlet with @MultipartConfig in order to let it recognize and support multipart/form-data requests and thus get getPart() to work:

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    // ...
}
Then, implement its doPost() as follows:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String description = request.getParameter("description"); // Retrieves
    Part filePart = request.getPart("file"); // Retrieves
    String fileName = getFileName(filePart);
    InputStream fileContent = filePart.getInputStream();
    // ... (do your job here)
}

private static String getFileName(Part part) {
    for (String cd : part.getHeader("content-disposition").split(";")) {
        if (cd.trim().startsWith("filename")) {
            String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
            return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
        }
    }
    return null;
}
This can all also be done in a Filter which does all the job transparently so that you can continue using the request.getParameter() the usual way. You can find an example in this article.

When you're already on Servlet 3.1 or newer

Since Servlet 3.1, the Part interface finally got a new method getSubmittedFileName() which returns the submitted filename, so the custom utility method isn't needed anymore.

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String description = request.getParameter("description"); // Retrieves
    Part filePart = request.getPart("file"); // Retrieves
    String fileName = filePart.getSubmittedFileName();
    InputStream fileContent = filePart.getInputStream();
    // ... (do your job here)
}
Workaround for GlassFish3 bug of getParameter() still returning null

Note that Glassfish versions older than 3.1.2 had a bug wherein the getParameter() still returns null. If you are targeting such a container and can't upgrade it, then you need to extract the value from getPart() as follows instead:

    String description = getValue(request.getPart("description")); // Retrieves
With this utility method:

private static String getValue(Part part) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
    StringBuilder value = new StringBuilder();
    char[] buffer = new char[1024];
    for (int length = 0; (length = reader.read(buffer)) > 0;) {
        value.append(buffer, 0, length);
    }
    return value.toString();
}
Saving uploaded file to disk - don't use getRealPath()!

Head to the following answers for detail on properly saving the obtained InputStream to disk (the fileContent variable as shown in the above code snippets):

recommended way to save files uploaded to a Tomcat servlet
How I save and retrieve an image on my server in a java webapp
answered May 21, 2015 by rajesh

...