Java Servlet – jQuery File Upload (multiple, drag&drop, progress…)

jQuery-File-Upload js library is “so far” the most elegant, smart, simple..etc js library I have used to upload files. Simply it is amazing. It supports async upload “Ajax”, multiple files upload, drag&drop, progress update and a lot more. Here we will see how to upload multiple files to Java “Servlet” app and how to deal with uploaded files using Java Servlet API or Apache FileUpload Library. Bootstrap has been used in this example to make the UI more attractive.

servlet-jquery-file-upload

Objectives:

Environment & Tools

  • Eclipse
  • Maven
  • Jetty (jetty-maven-plugin 9.x) or any other server supporting servlet 3.0
  • Browser (FireFox or Chrome)

Libraries:

Server side Java Libraries

  • Java Servlet API 3.0
  • Apache FileUpload
  • Jackson

Client side Javascript libraries

 

( 1 ) Project Structure servlet-jquery-file-upload-project

( 2 ) Server-Side “Back-end”

  • FileUploadServlet.java
  • MultipartRequestHandler.java
  • FileMeta.java
  • web.xml
  • /src/main/java/com/hmkcode/FileUploadServlet.java
  • FileUploadServlet.java is the servlet that will receive client request
  • It has two method, doPost() to handle file upload requests and doGet() to handle file download requests.
  • doPost() response content is in JSON format.
package com.hmkcode;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hmkcode.vo.FileMeta;

//this to be used with Java Servlet 3.0 API
@MultipartConfig 
public class FileUploadServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    // this will store uploaded files
    private static List<FileMeta> files = new LinkedList<FileMeta>();
    /***************************************************
     * URL: /upload
     * doPost(): upload the files and other parameters
     ****************************************************/
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{

        // 1. Upload File Using Java Servlet API
        //files.addAll(MultipartRequestHandler.uploadByJavaServletAPI(request));            

        // 1. Upload File Using Apache FileUpload
        files.addAll(MultipartRequestHandler.uploadByApacheFileUpload(request));

        // Remove some files
        while(files.size() > 20)
        {
            files.remove(0);
        }

        // 2. Set response type to json
        response.setContentType("application/json");

        // 3. Convert List<FileMeta> into JSON format
        ObjectMapper mapper = new ObjectMapper();

        // 4. Send resutl to client
        mapper.writeValue(response.getOutputStream(), files);

    }
    /***************************************************
     * URL: /upload?f=value
     * doGet(): get file of index "f" from List<FileMeta> as an attachment
     ****************************************************/
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{

         // 1. Get f from URL upload?f="?"
         String value = request.getParameter("f");

         // 2. Get the file of index "f" from the list "files"
         FileMeta getFile = files.get(Integer.parseInt(value));

         try {        
                 // 3. Set the response content type = file content type 
                 response.setContentType(getFile.getFileType());

                 // 4. Set header Content-disposition
                 response.setHeader("Content-disposition", "attachment; filename=\""+getFile.getFileName()+"\"");

                 // 5. Copy file inputstream to response outputstream
                InputStream input = getFile.getContent();
                OutputStream output = response.getOutputStream();
                byte[] buffer = new byte[1024*10];

                for (int length = 0; (length = input.read(buffer)) > 0;) {
                    output.write(buffer, 0, length);
                }

                output.close();
                input.close();
         }catch (IOException e) {
                e.printStackTrace();
         }

    }
}
  • /src/main/java/com/hmkcode/MultipartRequestHandler.java
  • MultipartRequestHandler.java will get uploaded files out of request object in one of two ways.
  • uploadByJavaServletAPI(): it gets all uploaded files using Java Servlet API. Note, this work with Servlet 3.0
  • uploadByApacheFileUpload(): it gets all uploaded files using Apache FileUpload lib.
package com.hmkcode;

import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.hmkcode.vo.FileMeta;

public class MultipartRequestHandler {

	public static List<FileMeta> uploadByJavaServletAPI(HttpServletRequest request) throws IOException, ServletException{

		List<FileMeta> files = new LinkedList<FileMeta>();

		// 1. Get all parts
		Collection<Part> parts = request.getParts();

		// 2. Get paramter "twitter"
		String twitter = request.getParameter("twitter");

		// 3. Go over each part
		FileMeta temp = null;
		for(Part part:parts){	

			// 3.1 if part is multiparts "file"
			if(part.getContentType() != null){

				// 3.2 Create a new FileMeta object
				temp = new FileMeta();
				temp.setFileName(getFilename(part));
				temp.setFileSize(part.getSize()/1024 +" Kb");
				temp.setFileType(part.getContentType());
				temp.setContent(part.getInputStream());
				temp.setTwitter(twitter);

				// 3.3 Add created FileMeta object to List<FileMeta> files
				files.add(temp);

			}
		}
		return files;
	}

	public static List<FileMeta> uploadByApacheFileUpload(HttpServletRequest request) throws IOException, ServletException{

		List<FileMeta> files = new LinkedList<FileMeta>();

		// 1. Check request has multipart content
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		FileMeta temp = null;

		// 2. If yes (it has multipart "files")
		if(isMultipart){

			// 2.1 instantiate Apache FileUpload classes
			DiskFileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload upload = new ServletFileUpload(factory);

			// 2.2 Parse the request
			try {

				// 2.3 Get all uploaded FileItem
				List<FileItem> items = upload.parseRequest(request);
				String twitter = "";

				// 2.4 Go over each FileItem
				for(FileItem item:items){

					// 2.5 if FileItem is not of type "file"
				    if (item.isFormField()) {

				    	// 2.6 Search for "twitter" parameter
				        if(item.getFieldName().equals("twitter"))
				        	twitter = item.getString();

				    } else {

				    	// 2.7 Create FileMeta object
				    	temp = new FileMeta();
						temp.setFileName(item.getName());
						temp.setContent(item.getInputStream());
						temp.setFileType(item.getContentType());
						temp.setFileSize(item.getSize()/1024+ "Kb");

				    	// 2.7 Add created FileMeta object to List<FileMeta> files
						files.add(temp);

				    }
				}

				// 2.8 Set "twitter" parameter 
				for(FileMeta fm:files){
					fm.setTwitter(twitter);
				}

			} catch (FileUploadException e) {
				e.printStackTrace();
			}
		}
		return files;
	}

	// this method is used to get file name out of request headers
	// 
	private static String getFilename(Part part) {
	    for (String cd : part.getHeader("content-disposition").split(";")) {
	        if (cd.trim().startsWith("filename")) {
	            String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
	            return filename.substring(filename.lastIndexOf('/') + 1).substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
	        }
	    }
	    return null;
	}
}
  • /src/main/java/com/hmkcode/vo/FileMeta.java

FileMeta is just a data model to hold file meta info and content.

package com.hmkcode.vo;

import java.io.InputStream;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties({"content"})
public class FileMeta {

	private String fileName;
	private String fileSize;
	private String fileType;
	private String twitter;

	private InputStream content;

//getters and setters...

}
  • /src/main/webapp/WEB-INF/web.xml

web.xml defines the servlet. Note, we are usign Servlet 3.0

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
id="WebApp_ID" version="3.0">
  <display-name>Archetype Created Web Application</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>

  <servlet>
  	<servlet-name>upload</servlet-name>            
  	<servlet-class>com.hmkcode.FileUploadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>upload</servlet-name>
  	<url-pattern>/upload</url-pattern>
  </servlet-mapping>
</web-app>

( 3 ) Client-Side “Front-end”

  • index.html
  • myuploadfunction.js
  • dropzone.css
  • /scr/main/webapp/index.html

HTML page structure: header, title, file input, drop zone & uploaded files table.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
<script src="js/jquery.1.9.1.min.js"></script>

<script src="js/vendor/jquery.ui.widget.js"></script>
<script src="js/jquery.iframe-transport.js"></script>
<script src="js/jquery.fileupload.js"></script>

<!-- bootstrap just to have good looking page -->
<script src="bootstrap/js/bootstrap.min.js"></script>
<link href="bootstrap/css/bootstrap.css" type="text/css" rel="stylesheet" />

<!-- we code these -->
<link href="css/dropzone.css" type="text/css" rel="stylesheet" />
<script src="js/myuploadfunction.js"></script>

<!-- header style ignore it -->
<link href="css/mystyle.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">

</head>

<body>
<div id="site-title-content">
		<h3 class="site-header"><a rel="home" title="HMKCode" href="http://hmkcode.com/">
      		HMKCode</a>
    	</h3>
    	<h4 class="site-description">
     	 	Code First!
	    </h4>
	</div>
<div id="header">
</div>
<div class="social-button icon">
		<a href="http://www.twitter.com/hmkcode" target="_blank" title="Visit Us On Twitter"><img src="img/twitter.png" style="border:0px;" alt="Visit Us On Twitter"></a>
		<a href="https://www.facebook.com/pages/HMKCode/157443611098005" target="_blank" title="Visit Us On Facebook"><img src="img/facebook.png" style="border:0px;" alt="Visit Us On Facebook"></a>
		<a href="https://plus.google.com/b/113117706677442855053/113117706677442855053" target="_blank" title="Visit Us On Google Plus"><img src="img/googleplus.png" style="border:0px;" alt="Visit Us On Google Plus"></a>
</div>

	<h1 style="text-align:center">Servlet jQuery File Upload<br></h1> 

	<!-- user twitter -->
	<div id="user_twitter">
	<span>Your Twitter</span>
		<div class="input-prepend">
			<span class="add-on">@</span>
			<input class="span2" id="twitter" name="twitter" type="text" placeholder="Username">
		</div>
	</div>
<div style="width:700px;padding:20px;S">

	<input id="fileupload" type="file" name="files[]" data-url="upload" multiple>

	<div id="dropzone" class="fade well">Drop files here</div>

	<div id="progress" class="progress">
    	<div class="bar" style="width: 0%;"></div>
	</div>
	<h5 style="text-align:center"><i style="color:#ccc"><small>Max File Size: 2 Mb - Display last 20 files</small></i></h5>

	<table id="uploaded-files" class="table">
		<tr>
			<th>File Name</th>
			<th>File Size</th>
			<th>File Type</th>
			<th>Download</th>
			<th>Uploaded By</th>
		</tr>
	</table>
</div>
</body> 
</html>
  • /scr/main/webapp/js/myuploadfunction.js

This JS function receives servlet JSON response and displays it in a tabular format.

$(function () {

    $('#fileupload').fileupload({

        dataType: 'json',

        done: function (e, data) {
        	$("tr:has(td)").remove();
            $.each(data.result, function (index, file) {

                $("#uploaded-files").append(
                		$('<tr/>')
                		.append($('<td/>').text(file.fileName))
                		.append($('<td/>').text(file.fileSize))
                		.append($('<td/>').text(file.fileType))
                		.append($('<td/>').html("<a href='upload?f="+index+"'>Click</a>"))
                		.append($('<td/>').text("@"+file.twitter))

                		)//end $("#uploaded-files").append()
            }); 
        },

        progressall: function (e, data) {
	        var progress = parseInt(data.loaded / data.total * 100, 10);
	        $('#progress .bar').css(
	            'width',
	            progress + '%'
	        );
   		},

		dropZone: $('#dropzone')
    }).bind('fileuploadsubmit', function (e, data) {
        // The example input, doesn't have to be part of the upload form:
        var twitter = $('#twitter');
        data.formData = {twitter: twitter.val()};        
    });

});
  • /scr/main/webapp/css/dropzone.css

This CSS is to style the drop zone

#dropzone {
    background: #ccccc;
    width: 150px;
    height: 50px;
    line-height: 50px;
    text-align: center;
    font-weight: bold;
}
#dropzone.in {
    width: 600px;
    height: 200px;
    line-height: 200px;
    font-size: larger;
}
#dropzone.hover {
    background: lawngreen;
}
#dropzone.fade {
    -webkit-transition: all 0.3s ease-out;
    -moz-transition: all 0.3s ease-out;
    -ms-transition: all 0.3s ease-out;
    -o-transition: all 0.3s ease-out;
    transition: all 0.3s ease-out;
    opacity: 1;
}

( 4 ) Run

To run this sample code using Maven

>mvn jetty:run

Source Code @ GitHub

3 thoughts on “Java Servlet – jQuery File Upload (multiple, drag&drop, progress…)

  1. atul

    Can you help me making a checkout for the code to eclipse by using plugin in eclipse ??
    i was looking for a tutorial but found very confusing for the import of the code via plugin

Comments are closed.