Page 1 of 3 123 LastLast
Results 1 to 10 of 27

Thread: File Upload Progress Bar

  1. #1
    Join Date
    Aug 2006
    Posts
    13

    Question File Upload Progress Bar

    Hi fellows,

    I'd like to know if there is any way to use a file upload progress bar, and continue using the MultiPartResolver ( & MultipartFile ) in form.

    I have a system with several forms, and lots of them use the MultiPartResolver to upload files, so I cant just forget it.

    I've seen this post, but it's exactly leaving the MultiPartResolver out of the scene.
    http://forum.springframework.org/sho...pload+progress

    I'd like to know if there is any way to continue using the MultiPartResolver, and still show a progress bar while spring uploads the file to MultiPartFile.

    I've looked around and around for that, with no success...

    I'm gratefull for any help... tks!

  2. #2
    Join Date
    Aug 2006
    Posts
    13

    Default Still no solution found...

    Hi dudes...

    I've still not found any solutions...

    Have anyone ran into this problem???

  3. #3

    Default These are my thoughts so far...

    I know this is an old thread, but figured i would add to it since it never got an answer and this is exactly what i am wanting to achieve.

    Basically i started by first extending every method in CommonsMultipartResolver and setting a break point on every method.

    Next i updated my bean definition to use my new class and did an upload and watched the order of the break points.

    The reason i did this was that i wanted to tie in a ProgressListener before the upload started, but i needed a FileUpload object to attach the listener to which is not configurable by a bean

    The ProgressListener is talked about here: http://commons.apache.org/fileupload/using.html in the watching progress section.

    Here is the method i chose to tie into
    Code:
    import org.apache.commons.fileupload.FileUpload;
    import org.apache.commons.fileupload.ProgressListener;
    import org.springframework.web.multipart.commons.CommonsMultipartResolver;
    
    public class MyCommonsMultipartResolver extends CommonsMultipartResolver {
        @Override
        protected FileUpload prepareFileUpload(String encoding) {
            FileUpload fileUpload = super.prepareFileUpload(encoding);
            ProgressListener progressListener = new ProgressListener() {
                public void update(long pBytesRead, long pContentLength, int pItems) {
                    System.out.println("We are currently reading item " + pItems);
                    if (pContentLength == -1) {
                        System.out.println("So far, " + pBytesRead + " bytes have been read.");
                    } else {
                        System.out.println("So far, " + pBytesRead + " of " + pContentLength + " bytes have been read.");
                    }
                }
            };
            fileUpload.setProgressListener(progressListener);
            return fileUpload;
        }
    }
    Basically i think i can tie the progress listener into some session status object that ajax dwr can access to report progress for the request. I know i should be injecting the ProgressListener in the constructor, but i will change that later.

    Here is how i configured dwr inside spring 2.0 as this took me a while to find and figure out. This will allow me to make an ajax dwr call to retrieve the session status from the ProgressListener and update a progress indicator.
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    			http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd">
    
    	<dwr:controller id="dwrController" debug="false" />
    
    	<dwr:configuration>
    		<dwr:convert type="bean" class="com.......domain.Object1">
    			<dwr:include method="id" />
    			<dwr:include method="display" />
    		</dwr:convert>
    		<dwr:convert type="bean" class="com......domain.Object2">
    			<dwr:include method="id" />
    			<dwr:include method="display" />
    		</dwr:convert>
    	</dwr:configuration>
    	<bean id="dwrService" class="com......ui.dwr.service.provider.DwrServiceProvider">
    		<constructor-arg>
    			<!-- inject WebContextFactory so JMock unit tests can mock this object -->
    			<bean class="org.directwebremoting.WebContextFactory" />
    		</constructor-arg>
    		<dwr:remote javascript="dwrService">
    			<dwr:include method="getSomethingMethod" />
    			<dwr:include method="getSomethingElseMethod" />
    		</dwr:remote>
    	</bean>
    	<!-- keep the dwr mappings separate from other mappings -->
    	<bean id="dwrMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    		<property name="order" value="1" />
    		<property name="alwaysUseFullPath" value="true"></property>
    		<property name="mappings">
    			<map>
    				<entry key="/dwr/**/*" value-ref="dwrController" />
    			</map>
    		</property>
    	</bean>
    </beans>
    Kevin.

    Hopefull someday tomorrow will come and i will let you all know if things worked! Or maybe someone else will have a solution! But now some sleep is needed but can't contain the excitement, but need sleep.....

  4. #4

    Default Working solution

    Ok, so i got a working solution by using ThreadLocal.

    Code:
    public class XyzMultipartResolver extends CommonsMultipartResolver {
        private static ThreadLocal<XyzProgressListener> progressListener = new ThreadLocal<XyzProgressListener>();
    
        @Override
        public void cleanupMultipart(MultipartHttpServletRequest request) {
            progressListener.get().setMultipartFinished();
            super.cleanupMultipart(request);
        }
    
        @Override
        protected FileUpload newFileUpload(FileItemFactory fileItemFactory) {
            FileUpload fileUpload = super.newFileUpload(fileItemFactory);
            fileUpload.setProgressListener(progressListener.get());
            return fileUpload;
        }
    
        @Override
        public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
            progressListener.set(new XyzProgressListener(request));
            return super.resolveMultipart(request);
        }
    }
    The methods are called in the following order as the upload thread executes on the server thru this class:
    1) resolveMultipart - This allows you to create a progress listener with the request object where it will place itself in session and become thread local here.
    2) newFileUpload - This allows your thread local progress listener (remember it is in session for lookup by your ajax caller) to be registered with the file upload object to monitor progress.
    3) cleanupMultipart - This allows for the progress listener to know when the upload is finished. This is important because what if your file upload does not know the content length.

    Some more notes.
    If you are doing multiple uploads at the same time, you will want to be able to identify each upload for monitoring progress. What i found is when resolveMultipart is called, you do not have access to any post parameters, but you do have access to the get parameters. Simply place your id for the upload as a get parameter on the upload form and you will then have the ajax progress bar find the correct progress listener you registered.

    I have this currently working for multiple simultaneous uploads each with its own progress bar and results displayed once finished. Works quite well i must say.

    Oh ya, and once your last ajax call gets a finished flag on the progress listener, have the ajax call trigger the progress listener to remove itself from session before returning the results to the ajax call to keep your session clean.

    Have fun!

  5. #5
    Join Date
    Nov 2007
    Posts
    8

    Default can you give more details?

    Hello,
    Could you please more details on how to integrate file upload progress bar in Spring? I haven't succeed with progress by now.
    If possible share all your files involved in upload and progress to understand what you have done.

  6. #6

    Default Some more info

    Here is a progress listener that you could use

    Code:
    public class XyzProgressListener implements ProgressListener {
        private long bytesRead = 0;
        private long contentLength = 0;
        private boolean multipartFinished = false;
    
        public XyzProgressListener(HttpServletRequest request) {
            request.getSession().setAttribute("ProgressListener_" + request.getParameter("id"), this);
        }
    
        @Override
        public void update(long bytesRead, long contentLength, int items) {
            this.bytesRead = bytesRead;
            this.contentLength = contentLength;
        }
    
        public void setMultipartFinished() {
            this.multipartFinished = true;
        }
    
        public boolean isFinished() {
            return multipartFinished;
        }
    
        public int getPercentDone() {
            if (contentLength == -1) {
                // ensure we never reach 100% but show progress
                return (int) Math.abs(bytesRead * 100.0 / (bytesRead + 10000));
            }
            return (int) Math.abs(bytesRead * 100.0 / contentLength);
        }
    }
    Now the class that dwr could call would be something like this
    Code:
    public class DwrServiceProvider implements DwrService {
        public DwrServiceProvider(WebContextFactory webContextFactory) {
            super();
            this.webContextFactory = webContextFactory;
        }
    
        public XyzProgressListener getProgress(String key) {
            WebContext webContext = webContextFactory.get();
            HttpServletRequest request = webContext.getHttpServletRequest();
            XyzProgressListener xpl = request.getSession().getAttribute("ProgressListener_" + key);
            if (xpl.isFinished()) {
                request.getSession().removeAttribute("ProgressListener_" + key);
            }
            return xpl;
        }
    }
    Now in the dwr xml configuration as provided in one of my above examples, simply expose the getProgress method for dwr in the dwrService bean and make sure you expose the percentDone method in the bean configuration for the progress listener.

    Following the spring mvc file upload documentation here simply register your XyzMultipartResolver instead of CommonsMultipartResolver and create a controller that extends SimpleFormController with a bean that contains a MultipartFile object for the uploaded file as described in the link to the spring docs.

    Right now i have to go do some other stuff. I will post again with some more info on how to trigger an upload in javascript and monitor the progress without submitting the form in the browser.

  7. #7

    Default html side of things

    Basically i did what this site talks about for the html and the form targeting the hidden iframe.

    I have javascript onchange with the upload form trigger a creation of the iframe and a new form inside a hidden div, then i move the file input dom object into the form and submit the form, reset the form and then move the file input dom object back to the place it came from. After that i trigger a timeout to dwr to monitor the progress. Dont forget to append an id key value pair to the form action and not as a hidden field. The form is also a post form and don't forget the enctype. The key allows everything to link together.

    The progress monitor javascript simply keeps setting a timeout and updating the progress bar and calling itself using a timeout until the upload is completed.

    That should provide you with everthing needed to put this together. Let me know how things go.

  8. #8
    Join Date
    Nov 2007
    Posts
    8

    Default File Upload Progress tutorial

    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.

  9. #9

    Default

    Thanks for the code

  10. #10
    Join Date
    Oct 2007
    Posts
    1

    Default

    Thank you for making the code available to everyone.
    I tried incorporating your code in my file upload page and I see message
    in error console that the argument for showStatus method is not defined
    when it is called in queryStatus method.

    Any thoughts, what might be the problem?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •