March 09, 2009

Multiple file upload using RESTful web service (Jersey)

For a web application, requirements comes in very interesting form. A typical challenging task is building a multiple file upload feature into web application. Regular Techno Paper readers know about "Multiple file upload using Struts" and how popular the solution is. Today, we will look at how to upload multiple files using a RESTful web service.

Let’s state the requirement more clearly. We need to provide the facility to upload multiple files on to the server using a REST web service. Users will have an “Add File” button that will present them with another file selection widget. Adding a new widget is done using the same java script we used in earlier articles. Still then, let’s have a look at the HTML coding first:
<html>
<head>
<script>
var fCount = 3;
function addFileElement() {
fCount++;
var fObject = document.getElementById('fileSection');
var text = 'File:';
var tag='<input type="file" name="fileup'+fCount+'" />';
var brk='<br>'
var o1 = document.createTextNode(text);
var o2 = document.createElement(tag);
var o3 = document.createElement(brk);
fObject.appendChild(o3);
fObject.appendChild(o1);
fObject.appendChild(o2);
fObject.appendChild(o3);
}
</script>
<title>Multiple file upload using JAX-RS</title>
</head>
<body>
<form action="jersey/fileupload" method="POST" enctype="multipart/form-data">
<div id="fileSection" >
File:<input type="file" name="fileup0" /><br>
File:<input type="file" name="fileup1" /><br>
File:<input type="file" name="fileup2" /><br>
</div>
<hr>
<input type="submit" value="Upload All files" />
<input type="button" onclick="addFileElement()" value="Add File"/>
</form>
</body>
</html>
The html code is very simple one with a form having action as the REST service’s URL. Also note that the method is POST and encoding type is multipart form. Form’s encoding type must be set to “multipart/form-data” for a file upload. In this example, initially I have provided three file selection fields in the form. On click of the button, a java script method “addFileElement” is called. The method simply creates a new file element and appends it to the form. You can modify this code to suit your requirements like limiting the number of file to a maximum of 7 files etc. You can also provide a facility to remove selected files. These modifications are left for people who will play with my code.

Building a REST web service is very simple. For this article also I have used the Jersey library. To extract files from the form data, I have used the Apache FileUpload module. Now let’s have a look at our REST resource class file:
@Path("fileupload")
public class FileUploadResource {
@POST
@Produces("text/plain")
public String loadFile(@Context HttpServletRequest request) {
String resultStatus="fail";
String fileRepository="I:\\testRepo\\";
if (ServletFileUpload.isMultipartContent(request)) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List items=null;
try {
items = upload.parseRequest(request);
} catch (FileUploadException e) {
e.printStackTrace();
}
if(items!=null) {
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = iter.next();
if(!item.isFormField() && item.getSize() > 0) {
String fileName = processFileName(item.getName());
try {
item.write(new File(fileRepository+fileName));
} catch (Exception e) {
e.printStackTrace();
}
resultStatus="ok";
}
}
}
}
return resultStatus;
}

private String processFileName(String fileNameInput) {
String fileNameOutput=null;
fileNameOutput = fileNameInput.substring(
fileNameInput.lastIndexOf("\\")+1,fileNameInput.length());
return fileNameOutput;
}
}
Notice that our resource’s access path is defined as: fileupload. This will match the action path specified in our HTML form. Also notice that we are processing HTTP POST method and not GET. To keep things simple, I am just returning a plain text back to the browser saying “ok” or “fail” as a status to the upload process.

loadFile method is the method called on submit of the form.The method has a injected parameter of type HttpServletRequest. This is to get access to the request object when the method is invoked. From the request we identify if the submitted data is a multipart data and then proceed in access the files in the request object using Apache FileUpload. Since the files are accessed as a List item, we can upload n number of files. The files are extracted using the API provided and stored into an appropriate location.

Let me know what you think of this solution. I am sure there are other methods to achieve the same task using REST web service. Your comments are welcome! You can grab the code as Eclipse project here!

You can enhance this code achieve more intersting things like uploading only image,adding constraint of file size, adding other form elements and validations.

12 comments :

Roby said...

Abdel, thanks for the nice blog.
May you also provide the related links which can be referred to get more information about jersey?

Olakara said...

Hi Roby,

You will find some basic tutorials @ http://wikis.sun.com/display/Jersey/Main.. I am sure there are other tutorials.. I will post them once I have a list. Right now, I am doing R&D and studying Jersey.. my current reference is mailing lists and javadocs :)

Pankhuri said...

Hi Roby,
Could you tell me how to upload a file by providing a relative path? If I do not know the installation directory of my server, but know that the file has to go in the /images folder, how do I store the image there?

Pankhuri said...

Sorry Abdel,
I meant to address it you

Olakara said...

@Pankhuri, you need a physical path to save a file. the /images folder will have its appropriate physical path. You will have to specify a absolute path when saving it on server.

Radhika Bhagavathula said...

I am not able to upload files with size like 20 MB using this method. Apache FileUpload seems to be breaking. Any help is appreciated.

Radhika Bhagavathula said...

I am not able to upload files with size like 20 MB or more with this method. Apache commons fileupload seems to be breaking. Any help is appreciated.

Mr A said...

There is a setSizeMax method in fileuploads' ServletFileUpload class could be set to increase the limit on upload file size.

ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
servletFileUpload.setSizeMax(300000); /* the unit is bytes */

anky2209 said...

hello everybody, I am new to javascript and want to upload a file. i have read client-side code for uploading a form but what about fetching it on server side???
So, if anyone could help me or point to some solution or can give some solution...pls do as early as possible....
THANKS..

kavita said...

How can we use the return value from the webservice??

Norma said...
This comment has been removed by a blog administrator.
Jacob Hubbard said...
This comment has been removed by a blog administrator.