
Originally Posted by
rsilviu
I succeeded implementing the file upload progress bar in my application with spring webflow and dwr.
I dind't find a quick and usable example on this forum so I'll explain what I did to work maybe someone will need it.
First I created a bean to keep the status of the upload:
public class UploadInfoBean {
private long totalSize = 0;
private long bytesRead = 0;
private int percentage = 0;
public int getPercentage() {
return percentage;
}
public void setPercentage(int percentage) {
this.percentage = percentage;
}
public long getTotalSize() {
return totalSize;
}
public void setTotalSize(long totalSize) {
this.totalSize = totalSize;
}
public long getBytesRead() {
return bytesRead;
}
public void setBytesRead(long bytesRead) {
this.bytesRead = bytesRead;
}
}
After that I implemented a listener to add to the multipartResolver and to call from client javascript to retrieve the upload status:
import java.text.NumberFormat;
import org.apache.commons.fileupload.ProgressListener;
import ro.theredpoint.routes.iris.beans.UploadInfoBean;
public class RoutesProgressListener implements ProgressListener {
private static long bytesTransferred = 0;
private static long fileSize = -100;
private long totalBytesRead = 0;
private long fiveKBRead = -1;
private UploadInfoBean uploadInfoBean = null;
public RoutesProgressListener() {
uploadInfoBean = new UploadInfoBean();
}
//function called from javascript to retrive the status of the upload
public UploadInfoBean getStatus() {
// per looks like 0% - 100%, remove % before submission
uploadInfoBean.setTotalSize(fileSize/1024);
uploadInfoBean.setBytesRead(totalBytesRead/1024);
String per = NumberFormat.getPercentInstance().format((double) bytesTransferred / (double) fileSize);
uploadInfoBean.setPercentage(Integer.parseInt(per. substring(0, per.length() - 1)));
return uploadInfoBean;
}
//function called by multipartResolver to notify the change of the upload status
public void update(long bytesRead, long contentLength, int items) {
// update bytesTransferred and fileSize (if required) every 5 KB is read
long fiveKB = bytesRead / 5120;
totalBytesRead = bytesRead;
if (fiveKBRead == fiveKB) {
return;
}
fiveKBRead = fiveKB;
bytesTransferred = bytesRead;
if (fileSize != contentLength) {
fileSize = contentLength;
}
}
}
After that I extended the CommonsMultipartResolver to add the listener:
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.servlet.ServletFileU pload;
import org.springframework.web.multipart.MaxUploadSizeExc eededException;
import org.springframework.web.multipart.MultipartExcepti on;
import org.springframework.web.multipart.MultipartHttpSer vletRequest;
import org.springframework.web.multipart.commons.CommonsM ultipartResolver;
import org.springframework.web.multipart.support.DefaultM ultipartHttpServletRequest;
public class RoutesMultipartResolver extends CommonsMultipartResolver {
private ProgressListener progressListener;
public void setProgressListener(ProgressListener progressListener) {
this.progressListener = progressListener;
}
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
String encoding = determineEncoding(request);
FileUpload fileUpload = prepareFileUpload(encoding);
if (progressListener != null){
fileUpload.setProgressListener(progressListener);
}
try {
List fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
MultipartParsingResult parsingResult = parseFileItems(fileItems, encoding);
return new DefaultMultipartHttpServletRequest(
request, parsingResult.getMultipartFiles(), parsingResult.getMultipartParameters());
}
catch (FileUploadBase.SizeLimitExceededException ex) {
throw new MaxUploadSizeExceededException(fileUpload.getSizeM ax(), ex);
}
catch (FileUploadException ex) {
throw new MultipartException("Could not parse multipart servlet request", ex);
}
}
}
In web.xml I mapped DispatcherServlet to dwr calls:
<servlet-mapping>
<servlet-name>routes</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
In *-servlet.xml I defined dwr controller and exposed needed methods from the bean:
<dwr:controller id="dwrController" debug="false" />
<dwr:configuration>
<dwr:convert type="bean" class="ro.theredpoint.routes.iris.beans.UploadInfo Bean"/>
</dwr:configuration>
<bean id="dwrUrlMapping" class="org.springframework.web.servlet.handler.Sim pleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
<property name="mappings">
<value>
/dwr/**/*=dwrController
</value>
</property>
</bean>
.................................................. ......
<bean id="routesProgressListener" class="ro.theredpoint.routes.multipartUpload.Route sProgressListener"
scope="session" >
<aop:scoped-proxy/>
<dwr:remote javascript="RoutesProgressListener">
<dwr:include method="getStatus"/>
</dwr:remote>
</bean>
I made a javaScript file for progress change:
function queryStatus() {
RoutesProgressListener.getStatus(showStatus);
return true;
}
function showStatus(status) {
if (status.percentage == "100"){
document.getElementById("progressBarText").style.v isibility = 'hidden';
document.getElementById("progressBarSuccesfull").s tyle.visibility = 'visible';
document.getElementById("progressBarBoxContent").s tyle.width = parseInt(status.percentage * 4) + "px";
} else {
document.getElementById("progressBarSuccesfull").s tyle.visibility = 'hidden';
document.getElementById("progressBar").style.displ ay = "block";
document.getElementById("percentage").innerHTML= ' ' + status.percentage;
document.getElementById("bytesRead").innerHTML= ' ' + status.bytesRead;
document.getElementById("totalSize").innerHTML= ' ' + status.totalSize;
document.getElementById("progressBarBoxContent").s tyle.width = parseInt(status.percentage * 4) + "px";
setTimeout(queryStatus, 500);
}
return true;
}
and the required css file:
#progressBar {
padding-top: 5px;
padding-left: 45px;
}
#progressBarText {
text-align: center;
margin-left: auto;
margin-right: auto;
color: #969696;
padding-left: 5px;
}
#progressBarBox {
width: 400px;
height: 20px;
border: 0px;
border-style: solid;
background-color: white;
margin-left: auto;
margin-right: auto;
}
#progressBarBoxContent {
background-color: #969696;
height: 20px;
}
#progressBarSuccesfull {
text-align: center;
margin-left: auto;
margin-right: auto;
color: #969696;
padding-left: 5px;
}
in my jsp file I imported the required js and css:
<style media="all" type="text/css">
@import url("css/progressUpload.css");
</style>
<script type='text/javascript' src='/routes-web/dwr/engine.js'> </script>
<script type='text/javascript' src='/routes-web/dwr/util.js'> </script>
<script type='text/javascript' src='/routes-web/dwr/interface/RoutesProgressListener.js'></script>
On my form I added:
<form:form name="submitFileForm" commandName="submitFile" method="post" enctype="multipart/form-data" onsubmit="setTimeout('queryStatus()', 200);">
and the div with progressBar:
<div id="progressBar" style="display: none;">
<div id="progressBarBox">
<div id="progressBarBoxContent"></div>
<div id="progressBarText">
<spring:message code="progressBarTransferLabel"/>
<span id="percentage"></span>
<spring:message code="progressBarProcentLabel"/>
<spring:message code="progressBarTransferSizeLabel"/>
<span id="bytesRead"></span>
<spring:message code="progressBarMetricUnitLabel"/>
<spring:message code="progressBarFromLabel"/>
<span id="totalSize"></span>
<spring:message code="progressBarMetricUnitLabel"/>;
</div>
<div id="progressBarSuccesfull">
<spring:message code="progressBarTextSuccessLabel"/></div>
</div>
</div>
I hope this will help anyone to implement a progress Bar in less time that I did. It toked me two days to make it work.
If someone has remarks about what I did or has ideas on how to improve this please reply to this post. I hope you understand my text because I didn't know how to format it better with scroll bars as above.