At line 3 changed 2 lines. |
!!!How to Create an AJAX based fileupload progressbar dialog |
This HOWTO shows how i combined [AJAX Struts File Upload Progress Meter|http://kencochrane.blogspot.com/2006/03/ajax-struts-file-upload-progress-meter.html] with a custom tweaked version of [Lightbox Gone Wild!|http://particletree.com/features/lightbox-gone-wild/] to create a user friendly upload progress bar dialog with the webpage below faded out. This means that users are unable to click on any links on the website and lets the visual indication of how much is left of the file transfer. |
!!!How to Create an AJAX based file upload progress-bar |
This tutorial shows how [AJAX Struts File Upload Progress Meter|http://kencochrane.blogspot.com/2006/03/ajax-struts-file-upload-progress-meter.html] has been combined with a custom tweaked version of [Lightbox Gone Wild!|http://particletree.com/features/lightbox-gone-wild/] to create a user friendly upload progress bar dialog with the web page below faded out. This means that users are unable to click on any links on the website and shows a the visual indication of how much is left of the file transfer. Its easy to customize the content of the dialog (see __{{lbContent}}__ in the section __Comments and tips__ section). |
At line 9 added 1 line. |
For newcomers to appfuse see [AppFuseQuickStart] as well as the videos at the top of the page [AppFuse] |
At line 72 changed 1 line. |
!!Install the serverside utility classes |
!!Install the serverside classes |
At line 107 added 3 lines. |
!Create the formbean |
Copy the attached file {{FileUploadForm.java}} (see bottom of this page) to the folder {{< Your project folder >\src\web\org\appfuse\webapp\}} |
|
At line 108 changed 4 lines. |
#Open the file {{< Your project folder >\properties.xml}} and find the element {{<path id="web.compile.classpath">}} |
# Add the followin lines to that element {{{ |
<pathelement location="${commons-fileupload.jar}"/> |
<pathelement location="${dwr.jar}"/> |
#Open the file {{< Your project folder >\properties.xml}} and find the element {{{<path id="web.compile.classpath">}}} |
# Add {{{<pathelement location="${commons-fileupload.jar}"/>}}} and {{{<pathelement location="${dwr.jar}"/>}}} |
|
The reult should be |
{{{ |
<!-- Web --> |
<path id="web.compile.classpath"> |
<pathelement location="${dist.dir}/${webapp.name}-dao.jar"/> |
<pathelement location="${dist.dir}/${webapp.name}-service.jar"/> |
<pathelement location="${struts.jar}"/> |
<pathelement location="${strutsmenu.jar}"/> |
<pathelement location="${displaytag.jar}"/> |
<pathelement location="${jakarta-oro.jar}"/> |
<pathelement location="${commons-digester.jar}"/> |
<pathelement location="${commons-logging.jar}"/> |
<pathelement location="${commons-beanutils.jar}"/> |
<pathelement location="${commons-collections.jar}"/> |
<pathelement location="${commons-fileupload.jar}"/> |
<pathelement location="${commons-lang.jar}"/> |
<pathelement location="${commons-validator.jar}"/> |
<pathelement location="${servletapi.jar}"/> |
<pathelement location="${commons-fileupload.jar}"/> |
<pathelement location="${dwr.jar}"/> |
<fileset dir="${javamail.dir}" includes="*.jar"/> |
<fileset dir="${spring.dir}" includes="*.jar"/> |
<fileset dir="${jstl.dir}/lib" includes="jstl.jar"/> |
</path> |
At line 141 added 47 lines. |
!!Configure decorators |
Update the file {{< Your project folder >\web\WEB-INF\decorators.xml}} with excludes for '/dwr/*' and '/engine.jsp*'. The content should now be: |
{{{ |
<decorators defaultdir="/decorators"> |
<excludes> |
<pattern>/resources/*</pattern> |
<pattern>/dwr/*</pattern> |
<pattern>/scripts/engine.jsp*</pattern> |
</excludes> |
<decorator name="default" page="default.jsp"> |
<pattern>/*</pattern> |
</decorator> |
</decorators> |
|
}}} |
|
!Notes for usage on previous Appfuse Versions |
|
This tutorial can also work on previous versions of Appfuse but you need to include the dependend AJAX framewords (they are by default included in Appfuse 1.9.3). You can grap prototype and scriptaculous from Appfuse 1.9.3 and place the scrips in the same folders as where they are placed in Appfuse 1.9.3. You also need to reference the Ajax frameworks in the decorator default.jsp. Below is an excerpt of the begining of {{default.jsp}} from the Appfuse 1.9.3 project used as basis for this tutorial. You specifically needs the lines that references "prototype.js" and "scriptaculous.js" in that order since "scriptaculous.js" depends on "prototype.js". __It's important to note__ that scriptaculous.js may load additionally js scrips. And this solution in thus tutorial also needs the effects.js to be available. But in order to be safe you should include them all. They are: |
*builder.js |
*effects.js |
*dragdrop.js |
*controls.js |
*slider.js |
__Excerpt of the beginning of default.jsp__ |
{{{ |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
|
<%@ include file="/common/taglibs.jsp"%> |
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> |
<head> |
<%@ include file="/common/meta.jsp" %> |
<title><decorator:title/> | <fmt:message key="webapp.name"/></title> |
|
<link rel="stylesheet" type="text/css" media="all" href="<c:url value='/styles/${appConfig["theme"]}/theme.css'/>" /> |
<link rel="stylesheet" type="text/css" media="print" href="<c:url value='/styles/${appConfig["theme"]}/print.css'/>" /> |
|
<script type="text/javascript" src="<c:url value='/scripts/prototype.js'/>"></script> <!-- THIS LINE IS NEEDED --> |
<script type="text/javascript" src="<c:url value='/scripts/scriptaculous.js'/>"></script> <!-- THIS LINE IS NEEDED --> |
<script type="text/javascript" src="<c:url value='/scripts/global.js'/>"></script> |
<decorator:head/> |
</head> |
... |
}}} |
|
|
At line 143 changed 1 line. |
In a browser open the url {{http://< your host>:8080/progressbar/dwr/}} (8080 is the default tomcat port, you may have changed this to 80 or somthing else) |
In a browser open the url {{http://< your host>:8080/progressbar/dwr/}} (8080 is the default tomcat port, you may have changed this to 80 or something else) |
At line 145 changed 1 line. |
!!Create css and javascript files |
You will need to login (the default admin username/pw is: mraible/tomcat). And gets to the DWR test page. Click the UploadMonitor link. That page click on the Execute button. |
At line 147 changed 1 line. |
!!Create the Struts Action |
The test should look like this image: |
[http://raibledesigns.com/wiki/attach/CreateAnAJAXBasedFileuploadProgressbarDialog/DWRTest.jpg] |
At line 149 changed 1 line. |
!!Create the Atruts JSP incliding the form |
!!Change the struts controller |
Update the file {{< Your project folder >\metadata\web\struts-controller.xml}} to use the new ExtendedMultiPartRequestHandler controler. The controler was added in the step __Install the serverside classes__. |
We also change the max upload size to 100M bytes. The content should now be: |
{{{ |
<controller nocache="true" inputForward="true" maxFileSize="100M" multipartClass="org.appfuse.webapp.action.fileupload.ExtendedMultiPartRequestHandler"/> |
}}} |
|
!!Configure Acegi |
Update the file {{< Your project folder >\web\WEB-INF\security.xml}} to allow annonymous access to the file {{/scrips/engine.jsp}}. Find the element starting with {{{<bean id="filterInvocationInterceptor" ... >}}} and add the line {{{/scripts/engine.jsp*=ROLE_ANONYMOUS,admin,user}}} as the last line of the {{{<value>}}} descendent tag. The content should now be: |
{{{ |
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> |
<property name="authenticationManager" ref="authenticationManager"/> |
<property name="accessDecisionManager" ref="accessDecisionManager"/> |
<property name="objectDefinitionSource"> |
<value> |
PATTERN_TYPE_APACHE_ANT |
/clickstreams.jsp*=admin |
/flushCache.*=admin |
/passwordHint.html*=ROLE_ANONYMOUS,admin,user |
/reload.*=admin |
/signup.html*=ROLE_ANONYMOUS,admin,user |
/users.html*=admin |
/**/*.html*=admin,user |
/scripts/engine.jsp*=ROLE_ANONYMOUS,admin,user |
</value> |
</property> |
</bean> |
}}} |
|
Redeploy the changes with the command: |
{{{ |
C:\projects\appfuse-1.9.3-src\progressbar>ant deploy |
}}} |
Restart tomcat |
|
Check that you can access the engine.jsp in a browser by opening the url {{http://< your host >:8080/scripts/engine.jsp}} (8080 is the default tomcat port, you may have changed this to 80 or somthing else) |
|
You should see the javascript content of the engine.jsp in the browser |
|
!!Create the form jsp, javascript and css files |
|
Extract the attached {{fileupload-js.zip}} (see bottom of this page) to {{< Your project folder >\web\}}. You should now have following files (and the exsisting ones) in your {{< Your project folder >\web\}} folder: |
{{{ |
$ find . |
. |
./images |
./images/ajax |
./images/ajax/activity.gif |
./images/ajax/indicator.gif |
./images/ajax/Thumbs.db |
./images/Thumbs.db |
./pages |
./pages/fileupload |
./pages/fileupload/fileUploadForm.jsp |
./scripts |
./scripts/dwrupload |
./scripts/dwrupload/dwrUpload.js |
./scripts/dwrupload/lightboxDwrUpload.js |
./scripts/engine.jsp |
./styles |
./styles/dwrupload |
./styles/dwrupload/dwrUpload.css |
./styles/dwrupload/lightboxDwrUpload.css |
}}} |
|
Redeploy the changes with the command: |
{{{ |
C:\projects\appfuse-1.9.3-src\progressbar>ant deploy-web |
}}} |
No need to restart tomcat this time |
|
!!Final test |
|
Now point your browser to {{http://< your host >:8080/editUploadFile.html}} login and test that it works. (you may have to reload the browser to ensure it loads the css and js files (Ctrl + r in FireFox and IE) ). Remember to pick a file of a certain size if you are uploading to localhost. You should now see this image: |
|
[http://raibledesigns.com/wiki/attach/CreateAnAJAXBasedFileuploadProgressbarDialog/dwrLightboxFileupload.jpg] |
|
!!!Comments and tips |
__Central files in this solution__ |
|
#__{{FileUploadAction.java}}__ - the struts Action responsible for reciving the uploaded files and save them to disk |
#__{{lightboxDwrUpload.js}}__ - The modified [Lightbox Gone Wild!|http://particletree.com/features/lightbox-gone-wild/] script used to fade the contend outside the upload dialog. This script looks copies the __{{.innerHtml()}}__ from the div tag with id __{{lbContent}}__ to the dialog. See next bullet. |
#__{{fileUploadForm.jsp}}__ and __{{lbContent}}__ - the JSP page containing the struts form. It contains a __{{lbContent}}__ div tag which represent the html code inserted in the upload dialog. It also contains an embedded javascript with the function __{{function upload(form)}}__ This script only trigger the upload mechanism if one or more files has been selected. |
#__{{dwrUpload.js}}__ - This script is the Ajax functions that updates the content of the upload dialog. You can tweak the dialog refresh rate here. |
#__{{ExtendedMultiPartRequestHandler.java}}__ - a slightly changed Struts controller (change marked by "Changed this section of code, that is it."). There is one important line here __{{{UploadListener listener = new UploadListener(request, 1);}}}__ The '1' here means delay to 1 millisecond. By increasing this value uploads will take longer time but will also be less CPU intensive. |
#__{{engine.jsp}}__ - is actually engine.js extracted from dwr1.x and tweaked to ensure dwr also works with cookies disabled. For details see "Support for DWR without cookies" [http://getahead.ltd.uk/dwr/fixes]. This issue is solved in version 2 of dwr. |
#__{{lightboxDwrUpload.css}}__ - Here the opacity can be specified. |
#__{{dwrUpload.css}}__ - Here the progress bar can be styled. |
|
__Change log4j to see whats going on__ |
|
In the file __{{log4j.properties}}__ change the line {{{log4j.rootCategory=DEBUG, mail}}} to {{{log4j.rootCategory=DEBUG, R}}} to get the log log messages written into a log file. |
|
__Additional thoughts__ |
|
I hope that this tutorial can serve as basis for integration into later Appfuse versions. It may also serve as a basis for similar tutorials for the other web frameworks that Appfuse provides. Actually it could be implemented in a servlet (See the original [AJAX Upload progress monitor for Commons-FileUpload Example|http://www.telio.be/blog/2006/01/06/ajax-upload-progress-monitor-for-commons-fileupload-example/]) instead of using the struts action and that servlet could be included in all the Appfuse versions to provide this functionality across the frameworks. |
|
__Productivity__ |
|
This page was created using one of Matt's productivity tips "[I've found that cracking open a beer at 11 when I start helps me focus and quit worrying about all the other computer-related tasks I need to do.|http://raibledesigns.com/page/rd?entry=tips_for_productivity_and_happiness]" - but I must say I needed to extended tip with a Whiskey.\\[http://raibledesigns.com/wiki/attach/CreateAnAJAXBasedFileuploadProgressbarDialog/productivity.jpg] |
|
__Related articles__ |
|
[AppFuseAjaxWithDWR] |
|
__Final note__ |
|
This tutorial is created by merging existing code into a new Appfuse project so I expect that the stuff work. In case of problems you can write to me at helge.tesgaard(a)gmail.com. Also write if you find typos or anything that can be explained better. |
|
Enjoy file transfers! |
|
Regards |
Helge |
|
|