In this post, you will learn how to code a Java client program that upload files to a web server programmatically.

In the article Upload file to servlet without using HTML form,we discussed how to fire an HTTP POST request to transfer a file to a server – but that request’s content type is not of multipart/form-data, so it may not work with the servers which handle multipart request and it requires both client and server are implemented in Java.

To overcome that limitation, in this article, we are going to discuss a different solution for uploading files from a Java client to any web server in a programmatic way, without using upload form in HTML code. Let’s examine this interesting solution now.

 

Code Java multipart utility class:

We build the utility class called MultipartUtilitywith the following code:

package net.codejava.networking;

import java.io.BufferedReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

/**
 * This utility class provides an abstraction layer for sending multipart HTTP
 * POST requests to a web server. 
 * @author www.codejava.net
 *
 */
public class MultipartUtility {
	private final String boundary;
	private static final String LINE_FEED = "\r\n";
	private HttpURLConnection httpConn;
	private String charset;
	private OutputStream outputStream;
	private PrintWriter writer;

	/**
	 * This constructor initializes a new HTTP POST request with content type
	 * is set to multipart/form-data
	 * @param requestURL
	 * @param charset
	 * @throws IOException
	 */
	public MultipartUtility(String requestURL, String charset)
			throws IOException {
		this.charset = charset;
		
		// creates a unique boundary based on time stamp
		boundary = "===" + System.currentTimeMillis() + "===";
		
		URL url = new URL(requestURL);
		httpConn = (HttpURLConnection) url.openConnection();
		httpConn.setUseCaches(false);
		httpConn.setDoOutput(true);	// indicates POST method
		httpConn.setDoInput(true);
		httpConn.setRequestProperty("Content-Type",
				"multipart/form-data; boundary=" + boundary);
		httpConn.setRequestProperty("User-Agent", "CodeJava Agent");
		httpConn.setRequestProperty("Test", "Bonjour");
		outputStream = httpConn.getOutputStream();
		writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
				true);
	}

	/**
	 * Adds a form field to the request
	 * @param name field name
	 * @param value field value
	 */
	public void addFormField(String name, String value) {
		writer.append("--" + boundary).append(LINE_FEED);
		writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
				.append(LINE_FEED);
		writer.append("Content-Type: text/plain; charset=" + charset).append(
				LINE_FEED);
		writer.append(LINE_FEED);
		writer.append(value).append(LINE_FEED);
		writer.flush();
	}

	/**
	 * Adds a upload file section to the request 
	 * @param fieldName name attribute in <input type="file" name="..." />
	 * @param uploadFile a File to be uploaded 
	 * @throws IOException
	 */
	public void addFilePart(String fieldName, File uploadFile)
			throws IOException {
		String fileName = uploadFile.getName();
		writer.append("--" + boundary).append(LINE_FEED);
		writer.append(
				"Content-Disposition: form-data; name=\"" + fieldName
						+ "\"; filename=\"" + fileName + "\"")
				.append(LINE_FEED);
		writer.append(
				"Content-Type: "
						+ URLConnection.guessContentTypeFromName(fileName))
				.append(LINE_FEED);
		writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
		writer.append(LINE_FEED);
		writer.flush();

		FileInputStream inputStream = new FileInputStream(uploadFile);
		byte[] buffer = new byte[4096];
		int bytesRead = -1;
		while ((bytesRead = inputStream.read(buffer)) != -1) {
			outputStream.write(buffer, 0, bytesRead);
		}
		outputStream.flush();
		inputStream.close();
		
		writer.append(LINE_FEED);
		writer.flush();		
	}

	/**
	 * Adds a header field to the request.
	 * @param name - name of the header field
	 * @param value - value of the header field
	 */
	public void addHeaderField(String name, String value) {
		writer.append(name + ": " + value).append(LINE_FEED);
		writer.flush();
	}
	
	/**
	 * Completes the request and receives response from the server.
	 * @return a list of Strings as response in case the server returned
	 * status OK, otherwise an exception is thrown.
	 * @throws IOException
	 */
	public List<String> finish() throws IOException {
		List<String> response = new ArrayList<String>();

		writer.append(LINE_FEED).flush();
		writer.append("--" + boundary + "--").append(LINE_FEED);
		writer.close();

		// checks server's status code first
		int status = httpConn.getResponseCode();
		if (status == HttpURLConnection.HTTP_OK) {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					httpConn.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null) {
				response.add(line);
			}
			reader.close();
			httpConn.disconnect();
		} else {
			throw new IOException("Server returned non-OK status: " + status);
		}

		return response;
	}
}
This utility class uses java.net.HttpURLConnection class and follows the RFC 1867 (Form-based File Upload in HTML) to make an HTTP POST request with multipart/form-data content type in order to upload files to a given URL. It has one constructor and three methods:

    • MultipartUtility(String requestURL, String charset): creates a new instance of this class for a given request URL and charset.
    • void addFormField(String name, String value): adds a regular text field to the request.
    • void addHeaderField(String name, String value): adds an HTTP header field to the request.
    • void addFilePart(String fieldName, File uploadFile): attach a file to be uploaded to the request.
    • List<String> finish(): this method must be invoked lastly to complete the request and receive response from server as a list of String.
Now let’s take a look at an example of how to use this utility class.

 

Code Java Client program to upload file:

Since the MultipartUtilityclass abstracts all the detailed implementation, a usage example would be pretty simple as shown in the following program:

package net.codejava.networking;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * This program demonstrates a usage of the MultipartUtility class.
 * @author www.codejava.net
 *
 */
public class MultipartFileUploader {

	public static void main(String[] args) {
		String charset = "UTF-8";
		File uploadFile1 = new File("e:/Test/PIC1.JPG");
		File uploadFile2 = new File("e:/Test/PIC2.JPG");
		String requestURL = "http://localhost:8080/FileUploadSpringMVC/uploadFile.do";

		try {
			MultipartUtility multipart = new MultipartUtility(requestURL, charset);
			
			multipart.addHeaderField("User-Agent", "CodeJava");
			multipart.addHeaderField("Test-Header", "Header-Value");
			
			multipart.addFormField("description", "Cool Pictures");
			multipart.addFormField("keywords", "Java,upload,Spring");
			
			multipart.addFilePart("fileUpload", uploadFile1);
			multipart.addFilePart("fileUpload", uploadFile2);

			List<String> response = multipart.finish();
			
			System.out.println("SERVER REPLIED:");
			
			for (String line : response) {
				System.out.println(line);
			}
		} catch (IOException ex) {
			System.err.println(ex);
		}
	}
}


In this program, we connect to the servlet’s URL of the application FileUploadSpringMVC (see this tutorial: Upload files with Spring MVC):

http://localhost:8080/FileUploadSpringMVC/uploadFile.do

We added two header fields, two form fields and two upload files under the name “fileUpload” – which must match the fields declared in the upload form of the FileUploadSpringMVC application.

When running the above program, it will produce the following output:

server response

We can realize that the server’s response is actually HTML code of the application FileUploadSpringMVC’s result page.

So far in this article, we’ve discussed about how to implement a command line program in Java which is capable of upload files to any URL that can handle multipart request, without implementing an HTML upload form. This would be very useful in case we want to upload files to a web server programmatically.

 

Related Java File Upload Tutorials:

 

Other Java network tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on Facebook and watch his Java videos you YouTube.



Attachments:
Download this file (MultipartFileUploader.java)MultipartFileUploader.java[Demo program]1 kB
Download this file (MultipartUtility.java)MultipartUtility.java[Utility class]4 kB

Add comment

   


Comments 

#117Thomas2023-01-25 09:15
Has anyone been able to get this code to actually upload a file? I have an api that works great from postman but can not get this code sample to connect to endpoint. Anyone?
Quote
#116seyha2021-12-08 19:34
Could you make another video how toupload multipart file size > 1GB ?
Quote
#115Wesley Workman2021-07-20 10:23
Quoting Jose Inciarte:
If you guys are getting two (2) extra bytes in your last file uploaded, it's because at line 130, writer.append(LINE_FEED).flush(); ...


This is 100% correct. I spent way too long chasing this down in my application. I greatly appreciate this utility, but it should be fixed to make it function correctly.
Quote
#114Jose Inciarte2021-07-01 13:33
If you guys are getting two (2) extra bytes in your last file uploaded, it's because at line 130, writer.append(LINE_FEED).flush(); appends another unnecessary LINE_FEED just before the flush is executed (LINE_FEED byte[] lenght is indeed 2, you can check it). So, you can perfectly change that line to writer.flush(); and there it is.
Quote
#113Dan E2021-01-28 11:15
Thx. Using this client code successfully.
I'm using custom server code to read and store the files on the server.
Is anyone using an existing library to process a multipart form? Would you have any info?
Thank you
Quote