Java Swing application to upload files to HTTP server with progress bar
- Details
- Written by Nam Ha Minh
- Last Updated on 04 May 2023   |   Print Email
In this tutorial, you will learn how to develop a Java Swing application that allows users uploading a file from his computer to a HTTP server. The application would look like this:
The following diagram explains workflow of the application:
As we can see, the client is a Swing application that initiates an HTTP POST request to the server. The request must be multipart in order to carry the file to be uploaded. The server side can be implemented in any language as long as it supports parsing HTTP’s multipart request.
For this tutorial, we only discuss how to implement the client side. For the server side, please consult the following tutorials:
The following class diagram gives an idea of how the application would be designed:
There are three main classes:
- MultipartUploadUtility: implements the functionality to upload a file to a server through HTTP’s multipart request. The implementation is based on the tutorial Upload files by sending multipart request programmatically, and is modified to suite requirement of this application: showing progress of the upload.
- UploadTask: this class extends the javax.swing.SwingWorker class to perform the upload in a background thread so the GUI does not freeze when the progress bar is being updated by the Swing’s event dispatching thread (EDT).
- SwingFileUploadHTTP: this is the main application which is a JFrame and displays the GUI. It implements the java.beans.PropertyChangeListener interface to be notified about the progress of upload which is sent by the UploadTask class. This class also utilizes the JFilePicker class to show a file chooser component. The JFilePicker in turn, uses the FileTypeFilter class. Refer to the article File picker component in Swing to see how these components are implemented.
Now let’s take closer look at how the main classes are implemented.
1. Code of the MultipartUploadUtility class
package net.codejava.swing.upload; import java.io.BufferedReader; import java.io.File; 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; /** * This utility class provides an abstraction layer for sending multipart HTTP * POST requests to a web server. * * @author www.codejava.net * */ public class MultipartUploadUtility { private final String boundary; private static final String LINE_FEED = "\r\n"; private HttpURLConnection httpConn; 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 MultipartUploadUtility(String requestURL, String charset) throws IOException { // creates a unique boundary based on time stamp boundary = "===" + System.currentTimeMillis() + "==="; URL url = new URL(requestURL); httpConn = (HttpURLConnection) url.openConnection(); httpConn.setDoOutput(true); // indicates POST method httpConn.setDoInput(true); httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); outputStream = httpConn.getOutputStream(); writer = new PrintWriter(new OutputStreamWriter(outputStream, charset), true); } /** * Add 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(); } /** * Write an array of bytes to the request's output stream. */ public void writeFileBytes(byte[] bytes, int offset, int length) throws IOException { outputStream.write(bytes, offset, length); } /** * Complete the request and receives response from the server. * * @throws IOException * if any network error occurred or the server returns * non-HTTP_OK status code. */ public void finish() throws IOException { outputStream.flush(); writer.append(LINE_FEED); writer.flush(); writer.append(LINE_FEED).flush(); writer.append("--" + boundary + "--").append(LINE_FEED); writer.close(); // check server's status code first int status = httpConn.getResponseCode(); if (status == HttpURLConnection.HTTP_OK) { BufferedReader reader = new BufferedReader(new InputStreamReader( httpConn.getInputStream())); while (reader.readLine() != null) { // do nothing, but necessary to consume response from the server } reader.close(); httpConn.disconnect(); } else { throw new IOException("Server returned non-OK status: " + status); } } }
2. Code of the UploadTask class
package net.codejava.swing.upload; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.swing.JOptionPane; import javax.swing.SwingWorker; /** * Executes the file upload in a background thread and updates progress to * listeners that implement the java.beans.PropertyChangeListener interface. * @author www.codejava.net * */ public class UploadTask extends SwingWorker<Void, Integer> { private String uploadURL; private File uploadFile; public UploadTask(String uploadURL, File uploadFile) { this.uploadURL = uploadURL; this.uploadFile = uploadFile; } /** * Executed in background thread */ @Override protected Void doInBackground() throws Exception { try { MultipartUploadUtility util = new MultipartUploadUtility(uploadURL, "UTF-8"); util.addFilePart("uploadFile", uploadFile); FileInputStream inputStream = new FileInputStream(uploadFile); byte[] buffer = new byte[4096]; int bytesRead = -1; long totalBytesRead = 0; int percentCompleted = 0; long fileSize = uploadFile.length(); while ((bytesRead = inputStream.read(buffer)) != -1) { util.writeFileBytes(buffer, 0, bytesRead); totalBytesRead += bytesRead; percentCompleted = (int) (totalBytesRead * 100 / fileSize); setProgress(percentCompleted); } inputStream.close(); util.finish(); } catch (IOException ex) { JOptionPane.showMessageDialog(null, "Error uploading 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(null, "File has been uploaded successfully!", "Message", JOptionPane.INFORMATION_MESSAGE); } } }
3. Code of the SwingFileUploadHTTP class
package net.codejava.swing.upload; 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 java.io.File; import javax.swing.JButton; 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 uploads files to a HTTP server. * @author www.codejava.net * */ public class SwingFileUploadHTTP extends JFrame implements PropertyChangeListener { private JLabel labelURL = new JLabel("Upload URL: "); private JTextField fieldURL = new JTextField(30); private JFilePicker filePicker = new JFilePicker("Choose a file: ", "Browse"); private JButton buttonUpload = new JButton("Upload"); private JLabel labelProgress = new JLabel("Progress:"); private JProgressBar progressBar = new JProgressBar(0, 100); public SwingFileUploadHTTP() { super("Swing File Upload to 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_OPEN); buttonUpload.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { buttonUploadActionPerformed(event); } }); 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(buttonUpload, constraints); constraints.gridx = 0; constraints.gridy = 3; 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 buttonUploadActionPerformed(ActionEvent event) { String uploadURL = fieldURL.getText(); String filePath = filePicker.getSelectedFilePath(); // validate input first if (uploadURL.equals("")) { JOptionPane.showMessageDialog(this, "Please enter upload URL!", "Error", JOptionPane.ERROR_MESSAGE); fieldURL.requestFocus(); return; } if (filePath.equals("")) { JOptionPane.showMessageDialog(this, "Please choose a file to upload!", "Error", JOptionPane.ERROR_MESSAGE); return; } try { File uploadFile = new File(filePath); progressBar.setValue(0); UploadTask task = new UploadTask(uploadURL, uploadFile); task.addPropertyChangeListener(this); task.execute(); } catch (Exception ex) { JOptionPane.showMessageDialog(this, "Error executing upload task: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } } /** * Update the progress bar's state whenever the progress of upload changes. */ @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress" == evt.getPropertyName()) { 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 SwingFileUploadHTTP().setVisible(true); } }); } }
4. Testing the application
To test the client program, we will use the file upload servlet application as described in the tutorial File Upload servlet with Apache Common File Upload API. So make sure you have the UploadServletApp application deployed on Tomcat server and notice URL of the servlet that handles file upload is:
http://localhost:8080/UploadServletApp/UploadServlet
Now launch the SwingFileUploadHTTP program. Enter the above URL into the Upload URL field, and click Browse button to pick a file:
Click Upload button to start uploading the file, and the progress bar shows progress of upload like this:
A message dialog appears when the upload is done:
In case of error, such as the Upload URL is mistyped, an error message appears like this:
You can download full source code and executable jar file of this application in the attachments section. There's also GitHub repository available for this project.
NOTE:the application must be compiled and executed with Java 1.6 or later.
Related Tutorials:
- Upload files by sending multipart request programmatically
- How to create File picker component in Swing
- Java File Upload Servlet Example
- Swing application to upload files to FTP server with progress bar
Other Java Coding Tutorials:
- 10 Common Mistakes Every Beginner Java Programmer Makes
- 10 Java Core Best Practices Every Java Programmer Should Know
- How to become a good programmer? 13 tasks you should practice now
- How to calculate MD5 and SHA hash values in Java
- How to generate random numbers in Java
- Java File Encryption and Decryption Example
Comments
thanks, you saved my life
You can use the addFormField() method of the MultipartUtility class here: codejava.net/.../...