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 gives 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 design at the end of this article.
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.
Table of Contents
Javascript Ajax Progress Bar Implementation
Let’s understand the implementation of the progress bar with sample points by referring to the below sample example-
- In the below example, we are taking some global variables(totalFileCount, fileUploadCount, fileSize) to store specific data.
- 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. - Before initiating the file uploads, we are calling the function
prepareProgressBarUI()
to design the progress bar UI. - Here we are using
XMLHttpRequest
a Javascript class object to do the Ajax call. You can see in the functionuploadFile()
. FormData
a class object is used to attach the multipart file usingappend()
method in order to upload it.- progress, load, and error are the events that are fired when file upload happens. So we are going to bind these events with function
onUploadProgress()
,onUploadComplete()
, andonUploadError()
respectively. - 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. - 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. - 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 for Ajax File Upload. In this application, the following files are required to develop:
- filesupload.html
- FileUploadServlet.java
- pom.xml
Ajax File Upload Application: 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 a progress bar example in Java. If you want to learn it in the Spring Boot application, visit another article
Spring Boot File Upload Progress bar.
Related Articles
- File upload validations in javascript
- Preview an image before uploading using Javascript
- Preview an image before uploading using jQuery
- File Upload in Java Servlet Example
- Multiple file uploads in Java with Progress bar – Ajax
- Step-by-step Java file upload | Ajax Progress bar