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.
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.
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
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
