Monitoring your file upload using ajax is a must have for any web 2.0 application. There are already some good examples developed by prosson and carsonm.

The first one looks great, but it is VERY slow. Takes several minutes to upload a file of 40M on localhost on my Core Duo which is Unnaceptable.

Fortunately, the second has the right speed. Actually, it has it all, being written with a prototype. The version I’m posting on this entry is just a variation to the version posted on mission data blog, using DWR. You can download all sources and dependencies along with Intellij IDEA project here.

The mechanism is simple and works like this:

  1. upload request is made with a dummy target (an embedded invisible iframe)
  2. on the server side, the upload servlet starts monitoring the upload and sets some objects on the session
  3. on the client side, a request for checking progress is made shortly after the upload has been triggered
  4. using DWR this request goes to a DWR proxy on the server side which returns some statistics
  5. when the upload servlet finished the upload, it will signal this to the DWR proxy, so that the next request for progress will be the last one

To integrate this in your own application you must do the following:

1. In web.xml declare the upload servlet and the dwr servlet (if it’s not there already):
    <servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>ro.tremend.upload.UploadServlet</servlet-class>
</servlet>

<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>scriptCompressed</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/Upload</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

2. In dwr.xml declare your proxy and a converter for the status object returned to UI:
    <create creator=”new” javascript=”uploadProxy”>
<param name=”class” value=”ro.tremend.upload.UploadProxy”/>
</create>

<convert converter=”bean” match=”ro.tremend.upload.UploadStatus”/>

3. In your jsp or html page add the following:
<iframe id=’target_upload’ name=’target_upload’ src=” style=’display: none’></iframe>

<form enctype=”multipart/form-data” name=”form” method=”post” action=”Upload” onsubmit=”return startUploadMonitoring();” target=”target_upload”>
File to upload: <input id=”importFile” name=”importFile” type=”file”> <br/>
<input id=”submitButton” type=”submit” value=”Upload”/>
</form>

<div id=”uploadStatus”>
<!– specify width on this uploadProgressBar, otherwise the progress indicator won’t move –>
<div id=”uploadProgressBar” style=”width:200px;”>
<div id=”uploadIndicator”></div>
</div>
<div id=”uploadPercentage”></div>
</div>

The iframe is used to swallow the response to the upload request. The form contains the upload fields and the button. The uploadStatus div will hold the progress monitor.

4. In the head section of your jsp or html you will have to add the following:

<style type=”text/css”>
#uploadStatus {
width: 230px;
}

#uploadProgressBar {
height: 14px;
border: 1px solid #BBB;
text-align: center;
display: inline;
float: left;
}

#uploadIndicator {
height: 10px;
position: relative;
margin: 1px;
padding: 1px;
background: #9DC0F4;
width: 0;
float: left;
}

#uploadPercentage {
width: 20px;
display: inline;
float: right;
}
</style>

<script type=’text/javascript’ src=”dwr/util.js”></script>
<script type=’text/javascript’ src=”dwr/engine.js”></script>
<script type=”text/javascript” src=”dwr/interface/uploadProxy.js”></script>

<script type=”text/javascript” language=”JavaScript”>
var updater = null;

function checkStatus() {
uploadProxy.getStatus(function(stat) {
if (stat.status == 2) {
updateProgressBar(100);
return;
}

if (stat.status == 3) {
alert(“An error has occured! ” + stat.message);
return;
}

if (stat.status == 4) {
alert(“An error has occured! ” + stat.message);
return;
}

// do something with the percentage (nice loading bar, simply show the percentage, etc)
updateProgressBar(stat.percentComplete);
window.setTimeout(“checkStatus()”, 500);
});
}

function updateProgressBar(percentage) {
// make sure you set the width style property for uploadProgressBar, otherwise progress.style.width won’t work
var progress = document.getElementById(“uploadProgressBar”);
var indicator = document.getElementById(“uploadIndicator”);
var maxWidth = parseIntWithPx(progress.style.width) – 4;
var width = percentage * maxWidth / 100;
indicator.style.width = width + “px”;
var perc = document.getElementById(“uploadPercentage”);
perc.innerHTML = percentage + “%”;
}

function parseIntWithPx(str) {
var strArray = str.split(“p”);
return parseInt(strArray[0]);
}

function startUploadMonitoring() {
window.setTimeout(“checkStatus()”, 500);
return true;
}
</script>

5. You can assign unique identifiers to the set of files you’re uploading. The UploadServlet will make sure when upload finished to make
all files available on the HttpSession object under the key you’ve specified. To do that you’ll have to:
    a) add a new field inside the form:
        <input type=”hidden” name=”uniqueFileIdentifier” value=”1234″/>
    b) in your java code, you can retrieve the files uploaded like this:
        List filesUploaded = (List) session.getAttribute(UploadServlet.FILES_UPLOADED);

This will return a list of FileItem objects (for more information check the commons file upload documentation).

 

technorati tags:, , , , ,

13 responses to “AJAX file upload monitoring – monitor your file upload with DWR and commons-fileupload

  1. This looks like just what I need. I’ve got the first solution you link to in place at the moment but, like you said, it’s very slow. Quick demo of your version is a lot faster. Thanks!

  2. Could you provide a .war file?
    I use Eclipse , and I can’t integrate your source in your own application correctly

  3. hi, i download the war file you provide, make no change,

    i seems it dose not work with a javascript error: uploadProxy is undefined.

    because i don’t familiar with DWR.

    thanks a lot!

  4. Hi Marius,

    it is really a very gut one solution. But I have a little problem with the upload from a file that is bigger than 50MB. The first way I try to upload it gives me a trouble message. By the second, third and so on, it goes. I could not find the bug. I think it’s a initializing problem, but where?

    Best Regards
    Vladimir

  5. its indeed a good solution. before came across this solution i spent couple of sleepless nights finding/implementing good solution for progress bar may be because i use low level API(multipartStream) to upload files. but I got lots of help from this article.

    only thing i need to know how secure DWR is ? or what things we need to care while configuring DWR for secure web application.

  6. Hi,

    Please help me in locating the file ‘dwr/interface/uploadProxy.js’. I am not able to run the application without this file and getting error. This file is not present in the ‘war’ file attached. Gembin had earlier pointed out this error “javascript error: uploadProxy is undefined”.

    Thanks & Regards,
    Abhishek

  7. Thanks, but i’m not getting the file uploadProxy.js at the path given by you …
    You hv said that “get an error first time when doing the upload – will have to fix it ” …. but how do I fix it for the first time ?

    Thanks & Regards,
    Abhishek

  8. serving up the uploadProxy.js from YOUR localhost doesn’t do the rest of us any good. Any chance you could post a better url?

  9. thank you very very good .war

    But i i’m getting an error with very large file (more than 2 gigas).
    Is anybody have an idea ?

Leave a Comment:

Your email address will not be published. Required fields are marked *