This tutorial is about how to build a Swing application that downloads a file from a HTTP server through a URL. The download application would look like this:

 Swing Download File HTTP application

Its workflow is explained in this diagram:

 SwingDownloadFileHTTP application workflow

The principal solution for this download application involves in using the java.net.HttpURLConnection class to initiates an HTTP connection with the server. The Swing client will parse HTTP headers sent from the server to determine information about the file to be downloaded such as file type, filename and content length. Then opening the HTTP connection’s input stream to read bytes transferred from the server. And an output stream is created on the client side to save the file on disk.

For more information about using HttpURLConnection class to download file, see the tutorial: Use HttpURLConnection to download file from an HTTP URL.

The following class diagram illustrates how the application will be designed:

SwingFileDownloadHTTP class diagram

As we can see, the application consists of the following classes:

    • HTTPDownloadUtil: encapsulates the core functionality of the application - download file from an HTTP URL. This class is implemented based on the tutorial Use HttpURLConnection to download file from an HTTP URL, but is modified to work with updating download progress while the file is being transferred.
    • DownloadTask: executes the file download in a background thread rather in the Swing’s event dispatcher thread (EDT), so the GUI will not become unresponsive when the download is taking place.
    • SwingFileDownloadHTTP: is the main application which displays the GUI that allows users to enter a download URL, choose a location to save the file, and start downloading.
    • JFilePicker and FileTypeFilter: These components are used by the SwingFileDownloadHTTP class to show a file chooser. These classes are taken from the article File picker component in Swing.

Let’s see how these classes are implemented in details.

 

1. Code of the HTTPDownloadUtil class

package net.codejava.swing.download;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * A utility that downloads a file from a URL.
 * 
 * @author www.codejava.net
 * 
 */
public class HTTPDownloadUtil {

	private HttpURLConnection httpConn;

	/**
	 * hold input stream of HttpURLConnection
	 */
	private InputStream inputStream;

	private String fileName;
	private int contentLength;

	/**
	 * Downloads a file from a URL
	 * 
	 * @param fileURL
	 *            HTTP URL of the file to be downloaded
	 * @throws IOException
	 */
	public void downloadFile(String fileURL) throws IOException {
		URL url = new URL(fileURL);
		httpConn = (HttpURLConnection) url.openConnection();
		int responseCode = httpConn.getResponseCode();

		// always check HTTP response code first
		if (responseCode == HttpURLConnection.HTTP_OK) {
			String disposition = httpConn.getHeaderField("Content-Disposition");
			String contentType = httpConn.getContentType();
			contentLength = httpConn.getContentLength();

			if (disposition != null) {
				// extracts file name from header field
				int index = disposition.indexOf("filename=");
				if (index > 0) {
					fileName = disposition.substring(index + 10,
							disposition.length() - 1);
				}
			} else {
				// extracts file name from URL
				fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
						fileURL.length());
			}

			// output for debugging purpose only
			System.out.println("Content-Type = " + contentType);
			System.out.println("Content-Disposition = " + disposition);
			System.out.println("Content-Length = " + contentLength);
			System.out.println("fileName = " + fileName);

			// opens input stream from the HTTP connection
			inputStream = httpConn.getInputStream();

		} else {
			throw new IOException(
					"No file to download. Server replied HTTP code: "
							+ responseCode);
		}
	}

	public void disconnect() throws IOException {
		inputStream.close();
		httpConn.disconnect();
	}

	public String getFileName() {
		return this.fileName;
	}

	public int getContentLength() {
		return this.contentLength;
	}

	public InputStream getInputStream() {
		return this.inputStream;
	}
}

This utility class does not actually download the file. It only makes a connection, parses HTTP headers to get file information, and opens the connection’s input stream which will be used by the DownloadTask class.


2. Code of the DownloadTask class

package net.codejava.swing.download;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

/**
 * Execute file download in a background thread and update the progress. 
 * @author www.codejava.net
 *
 */
public class DownloadTask extends SwingWorker<Void, Void> {
	private static final int BUFFER_SIZE = 4096;	
	private String downloadURL;
	private String saveDirectory;
	private SwingFileDownloadHTTP gui;
	
	public DownloadTask(SwingFileDownloadHTTP gui, String downloadURL, String saveDirectory) {
		this.gui = gui;
		this.downloadURL = downloadURL;
		this.saveDirectory = saveDirectory;
	}
	
	/**
	 * Executed in background thread
	 */	
	@Override
	protected Void doInBackground() throws Exception {
		try {
			HTTPDownloadUtil util = new HTTPDownloadUtil();
			util.downloadFile(downloadURL);
			
			// set file information on the GUI
			gui.setFileInfo(util.getFileName(), util.getContentLength());
			
			String saveFilePath = saveDirectory + File.separator + util.getFileName();

			InputStream inputStream = util.getInputStream();
			// opens an output stream to save into file
			FileOutputStream outputStream = new FileOutputStream(saveFilePath);

			byte[] buffer = new byte[BUFFER_SIZE];
			int bytesRead = -1;
			long totalBytesRead = 0;
			int percentCompleted = 0;
			long fileSize = util.getContentLength();

			while ((bytesRead = inputStream.read(buffer)) != -1) {
				outputStream.write(buffer, 0, bytesRead);
				totalBytesRead += bytesRead;
				percentCompleted = (int) (totalBytesRead * 100 / fileSize);

				setProgress(percentCompleted);			
			}

			outputStream.close();

			util.disconnect();
		} catch (IOException ex) {
			JOptionPane.showMessageDialog(gui, "Error downloading file: " + ex.getMessage(),
					"Error", JOptionPane.ERROR_MESSAGE);			
			ex.printStackTrace();
			setProgress(0);
			cancel(true);			
		}
		return null;
	}

	/**
	 * Executed in Swing's event dispatching thread
	 */
	@Override
	protected void done() {
		if (!isCancelled()) {
			JOptionPane.showMessageDialog(gui,
					"File has been downloaded successfully!", "Message",
					JOptionPane.INFORMATION_MESSAGE);
		}
	}	
}

This class implements the javax.swing.SwingWorker class so its doInBackground() method will be executed in a separate thread. It utilizes the HTTPDownloadUtil class to perform the file download, updates file information to the GUI and notifies download progress so the GUI will update the progress bar accordingly.


3. Code of the SwingFileDownloadHTTP class

package net.codejava.swing.download;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import net.codejava.swing.JFilePicker;

/**
 * A Swing application that downloads file from an HTTP server.
 * @author www.codejava.net
 *
 */
public class SwingFileDownloadHTTP extends JFrame implements
		PropertyChangeListener {
	private JLabel labelURL = new JLabel("Download URL: ");
	private JTextField fieldURL = new JTextField(30);

	private JFilePicker filePicker = new JFilePicker("Save in directory: ",
			"Browse...");

	private JButton buttonDownload = new JButton("Download");

	private JLabel labelFileName = new JLabel("File name: ");
	private JTextField fieldFileName = new JTextField(20);
	
	private JLabel labelFileSize = new JLabel("File size (bytes): ");
	private JTextField fieldFileSize = new JTextField(20);
	
	private JLabel labelProgress = new JLabel("Progress:");
	private JProgressBar progressBar = new JProgressBar(0, 100);
	
	public SwingFileDownloadHTTP() {
		super("Swing File Download from HTTP server");

		// set up layout
		setLayout(new GridBagLayout());
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.anchor = GridBagConstraints.WEST;
		constraints.insets = new Insets(5, 5, 5, 5);

		// set up components
		filePicker.setMode(JFilePicker.MODE_SAVE);
		filePicker.getFileChooser().setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

		buttonDownload.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				buttonDownloadActionPerformed(event);
			}
		});

		fieldFileName.setEditable(false);
		fieldFileSize.setEditable(false);
		
		progressBar.setPreferredSize(new Dimension(200, 30));
		progressBar.setStringPainted(true);

		// add components to the frame
		constraints.gridx = 0;
		constraints.gridy = 0;
		add(labelURL, constraints);

		constraints.gridx = 1;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		constraints.weightx = 1.0;
		add(fieldURL, constraints);

		constraints.gridx = 0;
		constraints.gridy = 1;
		constraints.weightx = 0.0;
		constraints.gridwidth = 2;
		constraints.fill = GridBagConstraints.NONE;
		add(filePicker, constraints);

		constraints.gridy = 2;
		constraints.anchor = GridBagConstraints.CENTER;
		add(buttonDownload, constraints);
		
		constraints.gridx = 0;
		constraints.gridy = 3;
		constraints.gridwidth = 1;
		constraints.anchor = GridBagConstraints.WEST;
		add(labelFileName, constraints);
		
		constraints.gridx = 1;
		add(fieldFileName, constraints);
		
		constraints.gridy = 4;
		constraints.gridx = 0;
		add(labelFileSize, constraints);
		
		constraints.gridx = 1;
		add(fieldFileSize, constraints);
		
		constraints.gridx = 0;
		constraints.gridy = 5;
		constraints.gridwidth = 1;
		constraints.anchor = GridBagConstraints.WEST;
		add(labelProgress, constraints);

		constraints.gridx = 1;
		constraints.weightx = 1.0;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		add(progressBar, constraints);

		pack();
		setLocationRelativeTo(null);	// center on screen
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);		
	}

	/**
	 * handle click event of the Upload button
	 */
	private void buttonDownloadActionPerformed(ActionEvent event) {
		String downloadURL = fieldURL.getText();
		String saveDir = filePicker.getSelectedFilePath();

		// validate input first
		if (downloadURL.equals("")) {
			JOptionPane.showMessageDialog(this, "Please enter download URL!",
					"Error", JOptionPane.ERROR_MESSAGE);
			fieldURL.requestFocus();
			return;
		}

		if (saveDir.equals("")) {
			JOptionPane.showMessageDialog(this,
					"Please choose a directory save file!", "Error",
					JOptionPane.ERROR_MESSAGE);
			return;
		}

		try {
			progressBar.setValue(0);

			DownloadTask task = new DownloadTask(this, downloadURL, saveDir);
			task.addPropertyChangeListener(this);
			task.execute();
		} catch (Exception ex) {
			JOptionPane.showMessageDialog(this,
					"Error executing upload task: " + ex.getMessage(), "Error",
					JOptionPane.ERROR_MESSAGE);
		}		
	}

	void setFileInfo(String name, int size) {
		fieldFileName.setText(name);
		fieldFileSize.setText(String.valueOf(size));
	}
	
	/**
	 * Update the progress bar's state whenever the progress of download changes.
	 */	
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if (evt.getPropertyName().equals("progress")) {
			int progress = (Integer) evt.getNewValue();
			progressBar.setValue(progress);
		}
	}
	
	/**
	 * Launch the application
	 */
	public static void main(String[] args) {
		try {
			// set look and feel to system dependent
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new SwingFileDownloadHTTP().setVisible(true);
			}
		});
	}	
}

This builds the user interface for the application and wires all the pieces together to form a complete application. To update the progress bar while the download is taking place, it “listens” to the property named “progress” which is repeatedly updated by the DownloadTask class.


4. Testing the application

To test this application, we need to have a downloadable URL, for example:

http://www.us.apache.org/dist/struts/source/struts-2.3.12-src.zip

Run the application and type the above URL into the Download URL field:

Test SwingFileDownloadHTTP program

Click Browse… button to select a directory where the file will be stored, for example: E:\Download, and hit Download button to start downloading the file. Just a second you will see the file information is updated in the fields File name and File size, as well as the progress bar gets updated quickly:

Swing Download File HTTP application

When the progress reaches to 100%, a message dialog appears:

download success message

The following error message dialog will appear in case of error such as the URL is invalid:

download error message

To experiment yourself with this nice application, download full source code and executable jar file of in the attachments section. You can also clone the sample project on GitHub.

NOTE:The application must be compiled and executed with Java 1.6 or later.

 

Related Tutorials:

 

Other Java Coding Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (SwingFileDownloadHTTP.zip)SwingFileDownloadHTTP.zip[Full source code and executable jar file]27 kB

Add comment

   


Comments 

#24Julian2023-11-06 04:30
Hekko Nam.
Thanks in advance
Quote
#23mei2021-01-24 05:21
bài làm rất hay, rất hữu ích
Quote
#22Sri2019-06-21 10:54
How to implement the cancel task? Need to add a background task cancellation part using a button action event. I'm struck with that. Could you help me with this?
Quote
#21aswini2017-07-29 07:38
How to run this code without having eclipse
Quote
#20avi2017-05-10 07:00
hii this example only one file download ....i want to multiple one by one file download give the status of each file.... how can do it
Quote