Implement File Upload and Download with Jakarta Servlet API

This tutorial demonstrates how to use the Jakarta Servlet API to build a file‑upload form with @MultipartConfig, configure upload limits in web.xml, and create a download servlet that sets proper Content‑Disposition headers, enabling seamless file transfer between client and server.

JakartaEE China Community
JakartaEE China Community
JakartaEE China Community
Implement File Upload and Download with Jakarta Servlet API

File upload with Jakarta Servlet

HTML form uses enctype="multipart/form-data" and posts to /upload. The servlet is annotated with @WebServlet("/upload") and @MultipartConfig specifying fileSizeThreshold = 1024 * 1024 (1 MB), maxFileSize = 1024 * 1024 * 5 (5 MB), maxRequestSize = 1024 * 1024 * 10 (10 MB). In init() the servlet reads the context parameter upload.path from web.xml, creates the directory if missing. In doPost() it obtains the Part named “file”, extracts the submitted filename, copies the input stream to ${upload.path}/${fileName} via Files.copy, and writes a success or error message.

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

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            Part filePart = request.getPart("file");
            String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();
            try (InputStream in = filePart.getInputStream()) {
                Files.copy(in, Paths.get(uploadPath, fileName));
            }
            response.getWriter().println("File uploaded successfully!");
        } catch (Exception e) {
            response.getWriter().println("File upload failed: " + e.getMessage());
        }
    }
}

Context parameter definition in web.xml:

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

File download with Jakarta Servlet

The download servlet is mapped to /download. It reads the same upload.path context parameter. The request must contain a file parameter with the filename. If the file exists, the servlet determines the MIME type via getServletContext().getMimeType(fileName), sets Content-Type, and adds a Content-Disposition header with the attachment directive so the browser downloads the file. The file is streamed to the response using a 4 KB buffer.

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

    @Override
    public void init() throws ServletException {
        uploadPath = getServletContext().getInitParameter("upload.path");
        File dir = new File(uploadPath);
        if (!dir.exists()) {
            dir.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, fileName);
        if (file.exists()) {
            String contentType = getServletContext().getMimeType(fileName);
            response.setContentType(contentType);
            response.setHeader("Content-Disposition",
                "attachment; filename=\"" + fileName + "\"");
            try (FileInputStream in = new FileInputStream(file);
                 OutputStream out = response.getOutputStream()) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }
        } else {
            response.getWriter().println("File not found on the server.");
        }
    }
}

Header syntax:

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

may be inline (display in browser) or attachment (force download). <filename> is the suggested name for the saved file when attachment is used.

Testing the download servlet: send a GET request such as http://localhost:8080/servlet-demo/download?file=myfile.txt.

File UploadWeb developmentFile DownloadJava EEJakarta ServletMultipartConfig
JakartaEE China Community
Written by

JakartaEE China Community

JakartaEE China Community, official website: jakarta.ee/zh/community/china; gitee.com/jakarta-ee-china; space.bilibili.com/518946941; reply "Join group" to get QR code

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.