Web applications frequently need to accept binary data such as profile pictures or spreadsheets from users. Standard form submissions encoded as application/x-www-form-urlencoded append data to the URL, which is unsuitable for large or binary payloads because URLs have length restrictions. The multipart/form-data encoding was introduced to overcome this limitation by splitting the request body into multiple parts, each representing a single form field.
------WebKitFormBoundaryBlo55fOFFMVhQ5pv
Content-Disposition: form-data; name="file"; filename="timg.jpeg"
Content-Type: image/jpeg
(binary content)
------WebKitFormBoundaryBlo55fOFFMVhQ5pv--
To send a file from an HTML form, the request must use the POST method, the enctype attribute must be set to multipart/form-data, and a file input field must be provided:
<form method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
HTML forms supporrt three encoding types:
- application/x-www-form-urlencoded – the default; encodes all characters before transmission.
- multipart/form-data – no character encoding; suitable for binary data.
- text/plain – spaces are converted to
+, but special characters remain unencoded.
Parsing a multipart/form-data request manually by reading the raw input stream (request.getInputStream()) is cumbersome because you need to split the body into individual parts and handle boundary separators. Apache Commons FileUpload simplifies this task and is widely adopted in Java web projects. It depends on Commons IO.
Add the following Maven dependency to your project:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
Commons FileUpload parses the entire request into a list of FileItem objects, each representing either a regular form field or an uploaded file. You can distinguish them by calling isFormField(). For normal fields you can retrieve the name and value; for uploaded files you can obtain the original file name, content type, size, and an input stream, or write the file directly to disk.
Below is a servlet example that extracts both textual fields and uploaded files using a clean, modern style:
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
@WebServlet("/upload")
public class FileUploadHandler extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
// Only proceed when the content type is multipart
if (!ServletFileUpload.isMultipartContent(request)) {
return;
}
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<fileitem> parts = upload.parseRequest(request);
for (FileItem entry : parts) {
if (entry.isFormField()) {
// Ordinary form field
String fieldName = entry.getFieldName();
String fieldValue = entry.getString("UTF-8");
// Process the text field as needed
} else {
// Uploaded file
String originalName = entry.getName();
File destination = new File("/var/lib/upload/" + originalName);
entry.write(destination);
}
}
} catch (Exception e) {
throw new RuntimeException("Failed to parse upload request", e);
}
}
}
</fileitem>