Ajax File Upload with Advance Progress Bar in Java

In this article, you will learn Ajax File Upload with Advance Progress Bar in Java. The file upload is a common functionality in most web applications. Nowadays the majority of people are focusing on user experience should be simple and smooth so when comes to file upload(single or multiple) the progress bar is giving the best user experience to any end-user. This article will show how we can develop an advanced progress bar design to achieve the best user experience.

To develop the below example we have used HTML, JavaScript, jQuery, Bootstrap, Ajax for the front-end design, and Java Servlet on the back-end side. Let’s have a look at the below screenshot, this is what you can able to design at the end of this article.

Ajax File Upload with Advance Progress Bar in Java

Here we are going to focus more on developing the advanced progress bar that is the front-end UI part. We have explained back-end (Server side) code in detail in another article File Upload in Java Servlet Example.

Javascript Ajax Progress Bar Implementation

Let’s understand the implementation of the progress bar with sample points by referring to the below sample example-

  1. In the below example we are taking some global variables(totalFileCount, fileUploadCount, fileSize) to store specific data.
  2. When the user clicks on the Upload file button, the function startUploading() will be called. This is the initiation function of file upload. Here we are initializing the defined global variables.
  3. Before initiating the file uploads, we are calling the function prepareProgressBarUI() to design the progress bar UI.
  4. Here we are using XMLHttpRequest a Javascript class object to do the Ajax call. You can see in the function uploadFile().
  5. FormData a class object is used to attach the multipart file using append() method in order to upload it.
  6. progress, load, and error are the event which is fired when file upload will be happening. So we are going to bind these events with function onUploadProgress(), onUploadComplete(), and onUploadError() respectively.
  7. The function onUploadProgress() will be continuously called and updated in the progress bar. Here e.loaded will tell how many bytes have been uploaded to the server, so based on that we are calculating the percentage of the progress bar.
  8. The function onUploadComplete() will be called when a file gets uploaded completely to the server. Here we are doing the next ajax call if more files are yet to be uploaded otherwise updating 100% for the progress bar.
  9. The function onUploadError() will be called when an error occurs while uploading the files.

Ajax file upload with progress bar Example

We are going to create an eclipse maven application. In this application the following files are required to develop:

  • filesupload.html
  • FileUploadServlet.java
  • pom.xml

Eclipse Project Structure

Ajax file upload example | eclipse project structure

filesupload.html

<!DOCTYPE PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>JavaCodePoint</title>
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<link rel="stylesheet"
	href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style>
.action-icon{padding:5px;cursor:pointer;color:#fff}
.table{font-size:11px;}
.table>tbody>tr>td{padding: 2px 6px;vertical-align: middle;border:none;}
#main-container{padding: 0px 20px 40px; width: 50%;margin:auto;}
#upload-status-container{display:none;}
#upload-header{height:35px;width:100%;background-color: #323254;color: #fff;padding: 8px;border-top-left-radius: 10px;border-top-right-radius: 10px;}
#progress-bar-container{padding:20px;max-height:260px;overflow-y:auto;border:1px solid #323254;}
::-webkit-scrollbar {background-color: #fff; width: 8px; height: 8px;}
::-webkit-scrollbar-thumb {background-color: #C0C0C0; border-radius: 10px;}
</style>
</head>
<body>
	<div id="main-container">
		<h3 class="text-info">Advance progress-bar file upload using Ajax</h3>
		<hr>
		<div style="margin-bottom: 20px">
			<input type="file" id="files" multiple style="margin-bottom: 20px" />
			<button class="btn btn-primary" type="button" onclick="startUploading()" ><i class="fa fa-upload"></i> Upload file</button>
		</div>
		<div id="upload-status-container">
			<div id="upload-header">
				<span id="upload-header-text"></span>
				<i class="action-icon fa fa-window-minimize pull-right" onclick="showHide(this)" title="minimize"></i>
			</div>
			<div id="progress-bar-container">
				<table class="table">
					<tbody></tbody>
				</table>
			</div>
		</div>
	</div>
</body>
<script>
	/* Globle variables */
	var totalFileCount, fileUploadCount, fileSize;

	/* start uploading files */
	function startUploading() {
		var files = document.getElementById('files').files;
		if(files.length==0){
			alert("Please choose at least one file and try.");
			return;
		}
		fileUploadCount=0;
		prepareProgressBarUI(files);
		
		// upload through ajax call		
		uploadFile();
	}
	
	/* This method will be called to prepare progress-bar UI */
	function prepareProgressBarUI(files){
		totalFileCount = files.length;
		var $tbody=$("#progress-bar-container").find("tbody");
		$tbody.empty();
		$("#upload-header-text").html("1 of "+totalFileCount+" file(s) is uploading");
		for(var i=0;i<totalFileCount;i++){
			var fsize=parseFileSize(files[i].size);
			var fname=files[i].name;
			var bar='<tr id="progress-bar-'+i+'"><td style="width:75%"><div class="filename">'+fname+'</div>'
			+'<div class="progress"><div class="progress-bar progress-bar-striped active" style="width:0%"></div></div></td>'
			+'<td  style="width:25%"><span class="size-loaded"></span> '+fsize+' <span class="percent-loaded"></span></td></tr>';
			$tbody.append(bar);
		}
		$("#upload-status-container").show();
	}
	
	/* parse the file size in kb/mb/gb */
	function parseFileSize(size){
		var precision=1;
		var factor = Math.pow(10, precision);
		size = Math.round(size / 1024); //size in KB
		if(size < 1000){
			return size+" KB";
		}else{
			size = Number.parseFloat(size / 1024); //size in MB
			if(size < 1000){
				return (Math.round(size * factor) / factor) + " MB";
			}else{
				size = Number.parseFloat(size / 1024); //size in GB
				return (Math.round(size * factor) / factor) + " GB";
			}
		}
		return 0;
	}

	/* one by one file will be uploaded to the server by ajax call*/
	function uploadFile() {
		var file = document.getElementById('files').files[fileUploadCount];
		fileSize = file.size;
		var xhr = new XMLHttpRequest();
		var fd = new FormData();
		fd.append("multipartFile", file);
		xhr.upload.addEventListener("progress", onUploadProgress, false);
		xhr.addEventListener("load", onUploadComplete, false);
		xhr.addEventListener("error", onUploadError, false);
		xhr.open("POST", "UploadServlet");
		xhr.send(fd);
		
	}

	/* This function will continueously update the progress bar */
	function onUploadProgress(e) {
		if (e.lengthComputable) {
			var percentComplete = parseInt((e.loaded) * 100	/ fileSize);
			var pbar = $('#progress-bar-'+fileUploadCount);
			var bar=pbar.find(".progress-bar");
			var sLoaded=pbar.find(".size-loaded");
			var pLoaded=pbar.find(".percent-loaded");
			bar.css("width",percentComplete + '%');
			sLoaded.html(parseFileSize(e.loaded)+ " / ");
			pLoaded.html("("+percentComplete+ "%)");
		} else {
			alert('unable to compute');
		}
	}

	/* This function will call when upload is completed */
	function onUploadComplete(e, error) {
		var pbar = $('#progress-bar-'+fileUploadCount);
		if(error){
			pbar.find(".progress-bar").removeClass("active").addClass("progress-bar-danger");
		}else{
			pbar.find(".progress-bar").removeClass("active");
			pbar.find(".size-loaded").html('<i class="fa fa-check text-success"></i> ');
		}
		fileUploadCount++;
		if (fileUploadCount < totalFileCount) {
			//ajax call if more files are there 
			uploadFile();
			$("#upload-header-text").html((fileUploadCount+1)+" of "+totalFileCount+" file(s) is uploading");
		} else {
			$("#upload-header-text").html("File(s) uploaded successfully!");
		}
	}

	/* This function will call when an error come while uploading */
	function onUploadError(e) {
		console.error("Something went wrong!");
		onUploadComplete(e,true);
	}
	
	function showHide(ele){
		if($(ele).hasClass('fa-window-minimize')){
			$(ele).removeClass('fa-window-minimize').addClass('fa-window-restore').attr("title","restore");
			$("#progress-bar-container").slideUp();
		}else{
			$(ele).addClass('fa-window-minimize').removeClass('fa-window-restore').attr("title","minimize");
			$("#progress-bar-container").slideDown();
		}
	}
</script>
</html>

FileUploadServlet.java

package com.javacodepoint.fileupload;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
 * 
 * @author javacodepoint
 *
 */
@WebServlet("/UploadServlet")
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, // 2MB
		maxFileSize = 1024 * 1024 * 500, // 500MB
		maxRequestSize = 1024 * 1024 * 1024) // 1GB
public class FileUploadServlet extends HttpServlet {
	
	/**
     * Location to save uploaded files on server
     */
	private static final String UPLOAD_PATH = "C:/uploads";
	
	/**
     * Method to get file name from HTTP header content-disposition
     */
	private String getFileName(Part part) {
		String contentDisp = part.getHeader("content-disposition");
		String[] items = contentDisp.split(";");
		for (String s : items) {
			if (s.trim().startsWith("filename")) {
				return s.substring(s.indexOf("=") + 2, s.length() - 1);
			}
		}
		return null;
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			File uploadsPath = new File(UPLOAD_PATH);
			if (!uploadsPath.exists()) {
				//create upload folder if not exist.
				uploadsPath.mkdir();
			}
			for (Part part : request.getParts()) {
				String fileName = getFileName(part);
				if(fileName!=null) {
					part.write(UPLOAD_PATH + File.separator + fileName);
				}
			}
			System.out.println("File uploaded successfully!");
		} catch (Exception e) {
			System.err.println("Error while uploading files!");
			e.printStackTrace();
		}
	}

}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javacodepoint</groupId>
	<artifactId>JavaFileUpload</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<dependencies>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.0.1</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.2.3</version>
				<configuration>
					<warSourceDirectory>WebContent</warSourceDirectory>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Conclusion

Here you have learned the Ajax file upload with progress bar example in java. If you want to learn it in the Spring Boot application, visit another article
Spring Boot File Upload with Advance Progress bar in Ajax.


Related Articles

You might like this

Share with friends

Leave a Comment

Your email address will not be published.