How to Upload and Download Files with a Servlet

This article will illustrate how to upload files using the Jakarta Servlet API. We will also learn how to use a Servlet to download a File that is available remotely on the Server.

Uploading Files with a Servlet

By using Jakarta Servlet API it is pretty simple to upload a File without the need of third party API. You can do that by setting the @MultipartConfig annotation within a Servlet. Let’s see a full example starting from an HTML page which contains the following form:

<!DOCTYPE html>
<html>
<head>
    <title>Servlet File Upload Example</title>
</head>
<body>
    <h1>Servlet File Upload Example</h1>
    <form action="upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="submit" value="Upload">
    </form>
</body>
</html>

Notice the enctype="multipart/form-data" attribute which specifies how to encode the form data before being sending it to the server.  You can use mainly two options here:

  • application/x-www-form-urlencoded (the default): you can use it for traditional form submissions where the form data is encoded in key-value pairs separated by “&” and spaces are replaced with “+” or “%20”.
  • multipart/form-data: you can use it for file uploads and other binary data. It creates a multipart request that allows files and non-ASCII data.

Next, let’s code the Upload Servlet:

@WebServlet("/upload")
@MultipartConfig(fileSizeThreshold = 1024 * 1024, // 1 MB
                 maxFileSize = 1024 * 1024 * 5,   // 5 MB
                 maxRequestSize = 1024 * 1024 * 10) // 10 MB
public class FileUploadServlet extends HttpServlet {
    private static String uploadPath=null;

    @Override
    public void init() throws ServletException{
        uploadPath= getServletContext().getInitParameter("upload.path");
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try {
            // Retrieve the file part from the request
            Part filePart = request.getPart("file");
            String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();

            // Save the file to the server
            InputStream inputStream = filePart.getInputStream();
            Files.copy(inputStream, Paths.get(uploadPath + File.separator + fileName));

            response.getWriter().println("File uploaded successfully!");
        } catch (IOException | ServletException e) {
            response.getWriter().println("File upload failed due to an error: " + e.getMessage());
        }
    }
}

The most interesting part is the MultipartConfig annotation which defines the settings to use for file upload:

  • fileSizeThreshold: This is the size threshold after which the file will be written to disk. The size value is in bytes.
  • maxFileSize: This is the maximum size (in bytes) allowed to upload a file. Its default value is -1L which means unlimited.
  • maxRequestSize: This is maximum size allowed for multipart/form-data request. The default value is -1L that means unlimited.

Within the doPost method, we retrieve the File from the request using the jakarta.servlet.http.Part and we write the InputStream to a File.

Please notice that this example relies on the following context parameter available in web.xml

<context-param>
  <param-name>upload.path</param-name>
  <param-value>/home/francesco/tmp</param-value>
</context-param>

The above parameter defines the location where you will store the files on the Server.

Deploy the application and request the index.html page to test it:

servlet upload and download files

You should be able to see the selected file in the “upload.path” folder of your server.

Using web.xml to define the  MultipartConfig

Instead of using the @MultipartConfig annotation to hard-code these attributes in your file upload servlet, you could also add the following as a child element of the servlet configuration element in the web.xml file.

<multipart-config>
    <location>/tmp</location>
    <max-file-size>20848820</max-file-size>
    <max-request-size>418018841</max-request-size>
    <file-size-threshold>1048576</file-size-threshold>
</multipart-config>

Downloading a File with a Servlet

In our second example, we will show how to download a file with a Servlet. We will be using the same Context Parameter also for the download Servlet, that is:

<context-param>
  <param-name>upload.path</param-name>
  <param-value>/home/francesco/tmp</param-value>
</context-param>

Additionally, we will provide the file name as Request parameter. Here is the Download Servlet:

@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
    private static String uploadPath=null;

    public void init() throws ServletException{
        uploadPath= getServletContext().getInitParameter("upload.path");
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }
    }

 

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
      
        String fileName = request.getParameter("file");
        if (fileName == null) throw new ServletException("You need to provide 'file' as parameter");

        File file = new File(uploadPath+ File.separator + fileName);
        if (file.exists()) {
           
            String contentType = getServletContext().getMimeType(fileName);

            // Set the content type and attachment header
            response.setContentType(contentType);
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

            try (FileInputStream inputStream = new FileInputStream(file);
                 OutputStream outputStream = response.getOutputStream()) {

                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            response.getWriter().println("File not found on the server.");
        }
    }
}

The most interesting part is how to determine the contentType from the fileName:

String contentType = getServletContext().getMimeType(fileName);

Then, using the appropriate content type for the file we are setting the Response Content-Disposition Header:

response.setContentType(contentType);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

The basic syntax of the Content-Disposition header is as follows:

Content-Disposition: <directive>; filename="<filename>"

Here’s a breakdown of the components:

  • <directive>: This can be either “inline” or “attachment.”
    • “inline”: The content should be displayed directly in the browser if possible.
    • “attachment”: The content should be treated as an attachment and downloaded.
  • <filename>: This is an optional parameter that provides the suggested filename to be used when saving the content as a file on the user’s device during download. It is ignored when the inline directive is used.

To test our Download Servlet, simply send a GET request which includes the file request parameter. For example:  http://localhost:8080/servlet-demo/download?file=myfile.txt

Conclusion

In this tutorial, we have learned how to implement file uploading and downloading with a Java Servlet using the plain Jakarta EE API. We explored the fundamental steps involved in handling file uploads and downloads, enabling you to build powerful web applications that allow users to interact with files on the server.

Recommended reading

If you want to check how to use a REST Endpoint to upload and download files check this article: Using REST Services to upload and download files

Source code: https://github.com/fmarchioni/mastertheboss/tree/master/web/file-upload

Found the article helpful? if so please follow us on Socials