Finally found the way to do the uploading via Flex to a Java backend. What i have used is the Spring Web MVC framework by making use of the example in the Spring Documentation on the multipart support #. The documentation does not include some of the necessary configuration such as the web.xml setup plus the controller and servlet configuration. It is pretty standard if you understand Spring.
The cool part about Spring’s multipart support is that we can simply extract the multipart file from the command object. Any multipart content will be identified by the multipartResolver which we will configure following the documentation.
So all the tricky part is left to be done on the Spring controller. And with a bit of java.io knowledge, our upload can be easily done in two hours. Yes two hours… i realised my mistake in using the file upload example in Spring Web Flow when i was testing with the Flex frontend upload example. At first, i thought it would be cool to make use of it but i guess i have to “Keep it sweet and simple”. So the spring dispatcher servlet approach. I am in love with Spring.
(Updated)References:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | public class ImageUploadController extends SimpleFormController { protected String fileUploadLocation; protected ModelAndView onSubmit( HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { // cast the bean - POJO FileUploadBean bean = (FileUploadBean) command; // let's see if there's content there MultipartFile imageFile = bean.getFile(); //Check upload file if (imageFile.getSize() == 0) { //the user did not upload anything throw new Exception("No file uploaded"); } //Get image filename String fileName = imageFile.getOriginalFilename(); int index = fileName.toLowerCase().indexOf("jpg"); String fileName = "test.jpg"; //Create new File Object String fileSeparator = System.getProperty("file.separator"); File newFile = new File(assetsLocation + fileSeparator + fileUploadLocation + fileSeparator + fileName); //check for file if (newFile.exists()) { try { // Create file if it does not exist boolean success = newFile.createNewFile(); if (success) { // File did not exist and was created System.out.println("File created"); } else { // File already exists System.out.println("File not created"); } } catch (IOException e) { // Handle your exception } } imageFile.transferTo(newFile); return super.onSubmit(request, response, command, errors); } } |
Web.Xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <servlet> <servlet-name>profileImageUpload</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>profileImageUpload</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping> imageUpload-servlet.xml <pre lang="xml" line="1"> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- Limit uploads to small (5KB) files for this sample --> <property name="maxUploadSize" value="5120" /> </bean> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="/WEB-INF/test.properties"/> </bean> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/upload.form">fileUploadController</prop> </props> </property> </bean> <bean id="fileUploadController" class="com.someclass.ImageUploadController"> <property name="fileUploadLocation"><value>${fileuploadimage.location}</value></property> <property name="assetsLocation"><value>${fileuploadimage.assets}</value></property> <property name="commandClass"><value>com.someclass.FileUploadBean</value></property> <property name="successView"><value>confirmation.jsp</value></property> </bean> </beans> |
Flex codes with some modification from the example at http://blog.flexexamples.com/2007/09/21/uploading-files-in-flex-using-the-filereference-class/ (By request of Tamitutor)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" verticalAlign="middle" creationComplete="init();"> <mx:Script> <![CDATA[ [Bindable] private var fileRef:FileReference; private const FILE_UPLOAD_URL:String = "http://localhost:8080/demo/upload.form"; private function init():void { fileRef = new FileReference(); fileRef.addEventListener(Event.SELECT, fileRef_select); fileRef.addEventListener(ProgressEvent.PROGRESS, progressHandler); fileRef.addEventListener(Event.COMPLETE, fileRef_complete); } private function browseAndUpload():void { fileRef.browse(); message.text = ""; } private function fileRef_select(evt:Event):void { try { message.text = "size (bytes): " + numberFormatter.format(fileRef.size); var request:URLRequest = new URLRequest(FILE_UPLOAD_URL); request.method = URLRequestMethod.POST; var uploaderReqVars:URLVariables = new URLVariables("var=samevalue"); request.data = uploaderReqVars; fileRef.upload(request, "file"); } catch (err:Error) { message.text = "ERROR: zero-byte file"; } } private function fileRef_progress(evt:ProgressEvent):void { progressBar.setProgress(Number(evt.bytesLoaded), Number(evt.bytesTotal)); } private function progressHandler(event:ProgressEvent):void { var file:FileReference = FileReference(event.target); progressBar.setProgress( Number(event.bytesLoaded), Number(event.bytesTotal)); } private function fileRef_complete(evt:Event):void { message.text += " (complete)"; } ]]> </mx:Script> <mx:NumberFormatter id="numberFormatter" /> <mx:ApplicationControlBar> <mx:Button label="Upload file" click="browseAndUpload();" /> <mx:Label id="message" /> <mx:ProgressBar id="progressBar" mode="manual" visible="true" /> </mx:ApplicationControlBar> </mx:Application> |
#1 by eugene on October 13, 2007 - 4:53 pm
Quote
bwahahahahahahahahahhahahaa
#2 by Ted on October 13, 2007 - 6:30 pm
Quote
What is so funny chua?
#3 by Robert on January 8, 2008 - 4:23 am
Quote
Any chance You’ll be posting the source code?
#4 by Ted on January 8, 2008 - 12:37 pm
Quote
Hi robert,
I can do that… drop by soon!
But i’ll post the basic stuff…
#5 by HelpMePlease on January 16, 2008 - 12:06 pm
Quote
Hi there,
I’m trying to do the same setup as you have, but I keep getting IOError #2038. Do you have the sample code?
Thanks much.
#6 by Ted on January 16, 2008 - 10:03 pm
Quote
Hi,
Have pasted sample flex code reference that i am using.
#7 by HelpMePlease on January 17, 2008 - 4:42 am
Quote
Thanks Ted. It works on my CFusion server, but not when I try to use my Java backend with Spring. Did you have to create an actual file that maps to the controller?
For example, I did :
/FileUpload.html = FileUpload
I specified FileUpload.html to Flex and then have all the logic to handle it in the controller for FileUpload.
#8 by Ted on January 17, 2008 - 11:34 am
Quote
Hi Help me please(will be good if u left a name),
I have pasted my form controller and some sample settings files, ie web.xml and the servlet setting file.
Have a go and see if it works for you.
Cheers!!
PS:Thanks for visiting =)
#9 by Tamitutor on September 26, 2008 - 8:17 am
Quote
Hey,
Like this post…Gave me some ideas about doing a hybrid of your approach and just a plain vanilla BlazeDS remote service. Thanks! But, quick question, what is your FileUploadBean class? According to your spring config it is a bean that obviously inherits the command but can you explain a little more about that as it obviously has something to do with holding the actual file byte data. How do you use this bean on the Flex side? Are you making a proxy actionscript version of it and then passing that via the file reference upload url? If you could include the FileUploadBean I think it would help your example tremendously.
Thanks,
Tami
#10 by Tamitutor on September 26, 2008 - 8:18 am
Quote
Oh yeah, and something from your Flex side as far as remoting this example would be great too!
#11 by Tamitutor on September 27, 2008 - 12:51 am
Quote
Never mind, found what you are referring to here: http://static.springframework.org/spring/docs/2.0.x/reference/portlet.html. Scroll down to the section 16.7. Multipart (file upload) support
#12 by Kenneth on September 27, 2008 - 10:40 am
Quote
Hi TamiTutor,
Glad you found the idea behind these codes.
Sorry i was too busy to reply you. I’ll post up my Flex codes in a while. =)
Cheers
#13 by Amer on September 30, 2008 - 9:20 am
Quote
Hi!
What if I want my images to be uploaded to one of my working directory. I mean i want it to be uploaded in for EXAMPLE web-inf/images…
How to do that? Thanks…
#14 by Kenneth on September 30, 2008 - 10:18 am
Quote
@Amer
Have a look at line 31 of my ImageUploadController.
That is where i construct the working directory and filename for all my file uploads.
You can try something like this.
#15 by Amer on September 30, 2008 - 3:09 pm
Quote
Hi Kenneth
There’s always an error: The system cannot find the path specified
By the way what’s assets location?
Thanks
#16 by Kenneth on September 30, 2008 - 4:04 pm
Quote
@Amer
assets location is a method injected property. In my code, i have assetsLocation and fileUploadLocation to give me flexibility in placing my file upload locations. assetsLocation is a global path where i placed all my assets like images for my Flex app and fileUploadLocation is relative folder within the assetsLocation.
I suggest you manually create the folder first or do some checks whether the folders exists.
#17 by Kenneth on September 30, 2008 - 4:06 pm
Quote
@Amer
forgot to add that i removed the setters for method injection for assetsLocation and fileUploadLocation in my codes and mistakenly left it in my codes. Pardon me for that.
#18 by Tamitutor on October 1, 2008 - 12:48 pm
Quote
K, I’ve got a hybrid solution of what you’ve done here but without using Spring MVC…I’m using Flash 10 (new FileReference with Loader.loadBytes()), Spring, and AMF/Flex to Java remoting. When I have time–if ever I have time–I’ll post my code here: http://tami.wright.name/blogger
#19 by Amer on October 7, 2008 - 8:42 am
Quote
Hi
All of my problems regarding image upload is now solved. Thanks
for this great tutorial…
But now I have another problem. How to retrieve the multipart image
file from a server and DIRECTLY put it in a let say canvas or panel or
image object in flex? What I did is I created a folder and I put the images
there. Is there a way to do that without using a directory or folder?
Thanks
#20 by Robert on October 14, 2008 - 8:20 pm
Quote
Whats is ..upload.form…?
#21 by Robert on October 14, 2008 - 8:25 pm
Quote
I have…
Error #2044: Unhandled IOErrorEvent:. text=Error #2038: File I/O Error.
at pl.view.form.component::uploader/init()[D:\works\projects\FLEX\FlexT\src\pl\view\form\component\uploader.mxml:16]
at pl.view.form.component::uploader/___uploader_Panel1_creationComplete()[D:\works\projects\FLEX\FlexT\src\pl\view\form\component\uploader.mxml:6]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:9051]
at mx.core::UIComponent/set initialized()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:1167]
at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\managers\LayoutManager.as:698]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.core::UIComponent/callLaterDispatcher2()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:8460]
at mx.core::UIComponent/callLaterDispatcher()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:8403]
#22 by Kenneth on October 14, 2008 - 9:09 pm
Quote
@Robert
upload.form is a urlmapping given to the file upload controller. You can give any mapping to it like upload.action…
I can’t tell much from your error. Try checking your file writing permissions on your folder..
#23 by baybora on December 2, 2008 - 1:11 am
Quote
Hello, you can upgrade this post, Try Flex Gumbo to upload and download (Filereference.load() function)
#24 by kennethteo on December 2, 2008 - 2:01 am
Quote
Yup you are right. I haven't had the time to upgrade to Gumbo. Will be doing a new set of post on flash player 10 and blazeds as well.
#25 by ade on March 4, 2009 - 8:05 am
Quote
may you show the script of upload.form?
thank before
#26 by Mohsin Naeem on April 5, 2009 - 1:52 pm
Quote
Can anyone please post a complete source code, I am using the same above mentioned configurations except for minor changes in the Controller and am ignoring the propertyConfigurator but whenever I upload a file none of the messages in the Controller class get printed in the tomcat console meaning it is somehow still not accessible to Flex.
#27 by kennethteo on April 5, 2009 - 2:06 pm
Quote
Hi Mohsin,
It's really the whole source code and app config.
Did you miss out the crossdomain policy file? Just wondering since you aren't getting anything on your tomcat.
#28 by David on April 9, 2009 - 6:05 am
Quote
Thank you for the great sample. Got this up and running in about an hour!
#29 by kennethteo on April 9, 2009 - 6:21 am
Quote
You're welcome, David… and that's fast!
So i suppose it is complete source code for you? I am just wondering whether i need to improve on this post…
#30 by thomas on May 5, 2009 - 12:59 pm
Quote
Thanks for the example.
Here is a solution using @nnotations : http://forum.springsource.org/showthread.php?t=57...
#31 by kennethteo on July 8, 2009 - 2:18 pm
Quote
Hi David,
I hope this helps. I have packaged a eclipse project here: http://kennethteo.com/files/FileUpload.zip
Download and import it into your eclipse workspace. For the compilation error that you will see, all you will need is to add your Server Library into your workspace. I assume you are using the eclipse JST plugin.
I know how it feels to get stuck
#32 by kennethteo on July 9, 2009 - 4:05 pm
Quote
Hi David,
From our discussion via email, it looks like adding the cross-domain policy file to your server made it work.
Glad it worked for you!
Cheers
#33 by Ashish on December 8, 2009 - 9:00 pm
Quote
hi kennethteo,
I have used your file upload code it is working fine I need return data from server side page on which I have written code of file upload I am using Asp.net handler to upload file on server
plz help me that how can I get the data from server side page when Image upload is complete event generated
#34 by Kenneth on December 8, 2009 - 9:11 pm
Quote
Hi Ashish,
You can try this on the server side: After the upload is done, redirect to a html page. You may want to display the file upload status on the html page so that your flex app can pick it up and act accordingly.
Hope it helps!