Flex to Java Servlet File Upload

The web’s insatiable appetite for upload functionality never ceases to amaze me. What do I mean? My little blog has around 100 posts of technology goodness. In the top five most trafficked posts are two articles I’ve done on uploading files. The more popular of the two goes all the way back to the days of Macromedia Central, and I still get random emails about it on a weekly basis. With that in mind, I decided it was time to revisit some of that old code with the latest tools and libraries.

Before I start let me say that as a matter of opinion, I think that this requirement to have content uploaded is a clear indicator for the need of Adobe AIR. In the browser, everything must to be uploaded first before it can be manipulated - and this is a major pain in the butt. There are clearly many times when an application’s workflow would be best suited by allowing the user to work with local files.

Now where was I … ? Ah, yes, file upload code.

Since most of the requests I get come from Java developers, this little tutorial will be centered around Java - specifically Servlet 2.5 with Tomcat 6.0.14 as the web container. I know that not everybody gets to run the latest and greatest though, and I’ve considered that during development. Most of the functionality I describe in the next several paragraphs can be easily duplicated and deployed to most Java web application containers (even much older ones).

I’m actually going to start in the HTML world, with a simple page that contains nothing more than an HTML form. This form contains two fields and a submit button. The first field is just a typical INPUT. I’ve included this extra field because I often get asked about how to handle more than just the file data.

<html>
<head>

<title>File Upload</title>

</head>
<body>

<form action="/examples/UploadExample" method="post" enctype="multipart/form-data">

Enter your name: <input name="person" type="text" value="Adobe" /><br />
Select a photo: <input name="photo" type="file" /><br />

<input type="submit" value="Upload" />

</form>

</body>
</html>

To submit a file, the form tag should have an encoding type of “multipart/form-data”. You’ll also want to point the form action at what will eventually by the servlet handling the upload operation. The input field for the file itself should have a type of “file”, which will tell the browser to present the appropriate browse button. Note that not every browser renders this input type the same, though there are some workarounds.

Although Servlet 2.5 is supposed to have support for file upload, I’ve found very little the way of documentation on the subject. The FileUpload library from Apache Commons however is very well documented, and is heavily used across the enterprise. Among the contributors is Martin Cooper, who I had a chance to meet briefly earlier this year at EMC World in Orlando. Martin is a growing Flex fan, and a real visionary - all the more reason for me to use this library.

Note that the FileUpload library does have dependencies, namely the Commons IO library. In the case of Tomcat, you can just drop these in the the “lib” directory and be on your way.

A form upload will come across as an HTTP POST operation, so you’ll need to implement the HttpServlet.doPost() method. The FileUpload library has great documentation, from which I’ve pulled most of the code. I wasn’t going for a robust implementation, I’ll leave that to you, I just wanted something that worked. The main points of interest are the DiskFileItemFactory and ServletFileUpload classes. Behind the scenes, these guys will parse the physical HTTP input stream and make it available to your servlet.

// Called when a file has been submitted
// Called because file uploads are HTTP POST operations
public void doPost( HttpServletRequest req, HttpServletResponse res )
{
  // Setup the various objects used during this upload operation
  // Commons file upload classes are specifically instantiated
  File disk = null;
  FileItem item = null;
  FileItemFactory factory = new DiskFileItemFactory();
  Iterator iter = null;
  List items = null;
  ServletFileUpload upload = new ServletFileUpload( factory );
  ServletOutputStream out = null;

  try
  {
    // Parse the incoming HTTP request
    // Commons takes over incoming request at this point
    // Get an iterator for all the data that was sent
    // TODO: Leverage generics
    items = upload.parseRequest( req );
    iter = items.iterator();

    // Set a response content type
    res.setContentType( "text/xml" );

    // Setup the output stream for the return XML data
    out = res.getOutputStream();
    out.println( "<response>" );

    // Iterate through the incoming request data
    while( iter.hasNext() )
    {
      // Get the current item in the iteration
      item = ( FileItem )iter.next();

      // If the current item is an HTML form field
      if( item.isFormField() )
      {
        // Return an XML node with the field name and value
        out.println( "<field name="" + item.getFieldName() + "" value="" + item.getString() + "" />"  );

        // If the current item is file data
      } else {
        // Specify where on disk to write the file
        // Using a servlet init param to specify location on disk
        // Write the file data to disk
        // TODO: Place restrictions on upload data
        disk = new File( getInitParameter( "uploadPath" ) + item.getName() );
        item.write( disk );

        // Return an XML node with the file name and size (in bytes)
        out.println( "<file name="" + item.getName() + "" size="" + item.getSize() + "" />"  );
      }
    }

    // Close off the response XML data and stream
    out.println( "</response>" );
    out.close();
  // Rudimentary handling of any exceptions
  // TODO: Something useful if an error occurs
  } catch( FileUploadException fue ) {
    fue.printStackTrace();
  } catch( IOException ioe ) {
    ioe.printStackTrace();
  } catch( Exception e ) {
    e.printStackTrace();
  }
}

I’ve chosen to return information about the POST data to the client in the form of XML. Handling return data from a file upload, especially when used as a psuedo-service for an RIA is another very popular question I receive, so if that’s your question, then you’ll want to watch that data closely. In short, the servlet is simply going to print XML as a response in place of the more common HTML.

In terms of more common patterns, the servlet should forward data to a JSP, and the JSP should actually render the XML.

When ServletFileUpload parses the request, it gets back a List of items. There’s items for each field that came across with the HTTP POST. Some of those fields might contain form data, and others may contain file data. You can get an Iterator from the List and then loop through the FileItem collection to get whatever it is that’s most important to you. When you do finally run across the file, create an instance of File and give it to FileItem.write() to put the file on disk.

Don’t forget to close your XML packet so you’ll have well-formed data.

Once you’ve got that servlet compiled, you’ll need to specify its configuration in your container’s “web.xml”. This configuration is what makes the path and name you specify in the HTML as the form action. Use whatever is most appropriate for your situation. The servlet entries I use are as follows. Note that I use an initialization parameter to specify the path on disk that I want to write the incoming files. This just always seemed easier to me than trying to use the servlet context.

<servlet>
  <servlet-name>UploadExample</servlet-name>
  <servlet-class>UploadServlet</servlet-class>
  <init-param>
    <param-name>uploadPath</param-name>
    <param-value>/Users/khoyt/Desktop/uploads/</param-value>
  </init-param>
</servlet>

...

<servlet-mapping>
  <servlet-name>UploadExample</servlet-name>
  <url-pattern>/UploadExample</url-pattern>
</servlet-mapping>

That’s it! Aside from a restarting of your container (or two), and some tweaking to the names/paths, you should now have a functioning file upload. Now the question is how to duplicate this traditional HTTP/HTML functionality with Flash?

I’ll be using Flex 3 for this example, though the code should work identically with Flex 2. If you’re interesting a public beta of Flex Builder 3 (as well as the Flex 3 SDK itself) is currently available on Adobe Labs. For those of you new to Flex, you can think of it as an application framework for Flash. No stage, timeline, library or other designer workflow to learn, just an Eclipse plug-in and good old XML. For what it’s worth however, the ActionScript 3 code should function almost identically inside Flash CS3.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	pageTitle="Upload Example"
	layout="absolute"
	creationComplete="doCreationComplete( event )"
	xmlns:mx="http://www.adobe.com/2006/mxml">

	...

	
	<mx:Label x="10" y="12" text="Enter your name:" />
	<mx:TextInput id="txtPerson" x="120" y="10" text="Adobe" />

	
	<mx:Label x="10" y="42" text="Select a photo:" />
	<mx:TextInput id="txtPhoto" x="120" y="40" editable="false" />
	<mx:Button x="288" y="40" label="Browse" click="doBrowse( event )" />

	
	<mx:Button x="10" y="70" label="Upload" click="doSubmit( event )" />

	
	<mx:TextArea id="txtResponse" left="10" top="100" right="10" bottom="10" />

</mx:Application>

There’s no exotic user interface here, just the same fields as what was represented in the HTML. Note that in Flash however we have exact control over the browse field and button and make them look like whatever we want. Aside from having to have some UI in general for the user to click on and prompt with a file selection dialog, you don’t even have to have a field. In fact, you could prompt the user immediately when the application started, and not have any buttons at all.

The Flex programming model is very event-driven and asynchronous. This just means that you’re going to listen for an event and do something when the user interacts with the UI. You don’t have to go around monitoring every last detail of the UI - it’ll let you know when it needs you.

File upload in Flash is accomplished through the FileReference class. I create an instance of it at the application level to be referenced periodically through the life of the application. When the application has finished all of its initial rendering, the “creation complete” event is triggered. It is here that I add two event listeners. The first listener will be triggered when the user has selected a file. The second listener will let the application know when it has received data in response to the upload operation (our XML data output from the servlet).

// Reference to the file on disk (selected by user)
public var file:FileReference = new FileReference();

// Called when the application has completed startup
public function doCreationComplete( event:Event ):void
{
  // Listen for when the user has selected a file
  // Listen for when the file upload is complete
  file.addEventListener( Event.SELECT, doSelect );
  file.addEventListener( DataEvent.UPLOAD_COMPLETE_DATA, doComplete );
}

When the user clicks the “Browse” button in the UI, we want them to be prompted with a file dialog box. Unlike HTML, with Flash that button may look like anything, or be any user gesture. The only reason the “Browse” button does this work is because I told it to listen for a click, and then prompt the user. My goal here was to mimic the HTML version of the upload as closely as possible to make understanding the example as easy as possible.

// Called when the "Browse" button is clicked
public function doBrowse( event:Event ):void
{
  // Prompt the user to select a file from disk
  file.browse();
}

// Called when the user selects a file from disk
public function doSelect( event:Event ):void
{
  // Puts the name of the selected file into the UI
  txtPhoto.text = file.name;
}

A FileReference cannot be populated without first interacting with the end user. This is a security feature in Flash to keep malicious applications from uploading your hard drive in the background. The exception to this rule however would be using Adobe AIR, which as an installed application has direct access to the local file system. With AIR this application could determine a file by itself and then upload that data without any user interaction.

A browse operation is initiated by calling FileReference.browse(). When the user selects a file, the aforementioned event is fired and we can take whatever following action we want. In this case, to function like the HTML form, I put the name of the file in an input field to display to the user. There’s also some other basic data about the file that’s available to Flash, such as it’s size in bytes. You cannot however read those bytes from Flash directly - if you’re not using AIR, you still have to upload the file data first for processing.

Again, Flash at this point could be uploading the file. In the HTML world we generally wait for the user to click a submit button. To keep as close parity as possible, I’ve chosen to include a button labeled “Upload” just like the HTML form. When this button gets clicked an event will get raised, and I can take action to being the upload process. It is at this point where things get a little more interesting, and we want to do some additional work to mimic the HTML form behavior.

// Called when the "Submit" button is clicked
// Initiates file upload operation
public function doSubmit( event:Event ):void
{
  // Specify the endpoint for the upload operation
  // Create an object to hold additional data fields
  var request:URLRequest = new URLRequest( "/examples/UploadExample" );
  var vars:URLVariables = new URLVariables();

  // Set the data fields as appropriate
  vars.person = txtPerson.text;

  // Assign the data fields to the request
  request.data = vars;

  // Start the file upload process
  file.upload( request );
}

Flex doesn’t track a form block in the same sense as HTML (it’s more for validation purposes in Flex), so we haven’t specified any “action” just yet. The first step then is to create an instance of the URLRequest class that will point to our upload endpoint (the servlet). The URLRequest instance will also handle all the other HTTP minutia as necessary. In this case that minutia is that additional form field data.

Form field data is represented in ActionScript with the URLVariables class. An instance here will allow us to create the name/value pairing that HTTP generally send across to the server. Notice that the name/value pairing is whatever I determine and is attached directly to URLVariables through dot-notation.

For most Java folks this will seem pretty odd as there’s no data type, collection or access methods for this data. ActionScript allows us to append values to the Object class directly during runtime. ActionScript can also see what properties have been added to the instance, which is referenced very similar in nature to JavaScript in the browser. We simply chose the name of the field, and make that property, assigning to it the value we want to submit. It seems kind of loose, but it’s actually very concise and powerful.

The actual upload itself is done by the FileReference class via FileReference.upload(). The FileReference.upload() method take the URLRequest instance as an argument so it knows where and what to submit.

When the upload is complete, and we get data back, an “upload complete data” event will be fired. In this case, that gets raised as a specific event type, DataEvent. The DataEvent object gives you access to the data that was returned. In this case, I simply grab the raw text and dump it into a text area. Since the result is an XML packet, you could go further and treat it as such using the various XML-related classes in ActionScript. A little E4X and data-binding and you’re on the road to a file upload RIA.

// Called when the upload operation has completed
// Specifically manages response data
public function doComplete( event:DataEvent ):void
{
  // Displays raw response data as a string
  txtResponse.text = event.data;
}

One specific feature I’ve left out is the ability in Flash to be able to listen for upload progress, and then to display that progress to the user. HTML doesn’t give us access to this information since it was designed with the page refresh in mind. Flash however won’t have to refresh itself and can display the progress in the UI directly. This really is simply a matter of registering for the “progress” event and processing the ProgressEvent.bytesLoaded against ProgressEvent.bytesTotal.

Hopefully this has proved a useful overview of file upload operations using Flash with a Java EE infrastructure. For all the functionality I’ve tried to cover, I’ve had to leave out quite a bit of detail. As I said at the outset of this article, I get weekly emails on this topic, and I’ll continue to monitor those requests. In the meantime, the complete source code for everything mentioned in this article is attached and available for download. Please do let me know if you have any further questions, or would like any additional topic coverage.

25 Responses to “Flex to Java Servlet File Upload”

  1. robert Says:

    hello,
    i am trying to get a fileupload with flex and air to work,
    may be you can post the soucres you used, please?

    greetings robert

  2. Kevin Hoyt Says:

    Robert,

    The source code is included with the post. In the last paragraph look for the link around the words “source code”.

    Thanks for reading,
    Kevin

  3. Laurie Hall Says:

    Hi Kevin,

    Thanks so much for this post, I’ve been looking all over for possible methods of uploading using java. This is about as comprehensive as you can get!

    Thanks!
    Laurie

  4. boukalane Says:

    i tried this example but the file is not uploaded.i’m using tomcat.
    i think that i can’t upload picture cos i don’t have the full file path.
    help plz.
    thx

  5. marius Says:

    boukalane use this line :
    disk = new file(getServletContext().getRealPath(getInitParameter(”uploadPath”)) + “\\” + item.getName() );

  6. boukalane Says:

    marius
    thx man , it’s working now , u saved my life ;-)

  7. raj Says:

    I’m trying your example, but running into trouble. I guess I’m missing some basics here, I’d really like to see your folder setup of this project (as I assume that it is not the same as the on the zip-file).

    Thanks,

    Raj

  8. Psylo Says:

    Thx for this nice and helpful article.

  9. Raj Says:

    This article was just i was looking. Thanks a lot. How do we browser and select multiple files using flash and upload to servlet

    Thanks,
    Raj

  10. Zdenek M Says:

    I am trying to run the file upload on AIR, but there is a strange behavior: when I select file using its path on local disk - new File(”path”) - the file is uploaded but I do not get any response from servlet. With file selected in browse dialog everything goes as expected, including the response.
    Regards
    Zdenek

  11. David Fader Says:

    I have been using Flex to create my RIAa. I was starting to work on an uploader to TomCat when I came across this article. I was done in 20 minutes. Your excellent example saved me two days of work. Nice job!

  12. baji Says:

    Thanks for the nice article..I am trying to do file upload from flex 3 to java..
    request is not at all coming to my servlet..If I use jsp then request is coming to jsp..am not sure what is problem to invoke servlet..
    Any help would be appreciated..
    I am getting following error..

    Error #2038: File I/o Error :URL:http://171.189.87.49:7001/WSTest/action/FileServlet.

    here is my code:

    Apollo.mxml
    …………

    –>

    Servlet:
    ………

    package com.boa.flex.servlet;

    import java.io.File;
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.List;

    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileItemFactory;
    import org.apache.commons.fileupload.FileUploadException;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    /**
    * @author nbkzk5e
    *
    */
    public class UploadFileServlet extends HttpServlet
    {
    /* (non-Javadoc)
    * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
    */

    private static final Log log = LogFactory.getLog(UploadFileServlet.class);
    //@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    super.doGet(req, resp);
    doPost(req,resp);
    }

    //@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException {

    File disk = null;
    FileItem item = null;
    FileItemFactory factory = new DiskFileItemFactory();
    Iterator iter = null;
    List items = null;
    ServletFileUpload upload = new ServletFileUpload( factory );
    ServletOutputStream out = null;

    try
    {
    // Parse the incoming HTTP request
    // Commons takes over incoming request at this point
    // Get an iterator for all the data that was sent
    // TODO: Leverage generics
    log.info(”am in servlet”);
    items = upload.parseRequest( req );
    iter = items.iterator();

    // Set a response content type
    res.setContentType( “text/xml” );

    // Setup the output stream for the return XML data
    out = res.getOutputStream();
    out.println( “” );

    // Iterate through the incoming request data
    while( iter.hasNext() )
    {
    // Get the current item in the iteration
    item = ( FileItem )iter.next();

    // If the current item is an HTML form field
    if( item.isFormField() )
    {
    // Return an XML node with the field name and value
    out.println( “” );

    // If the current item is file data
    } else {
    // Specify where on disk to write the file
    // Using a servlet init param to specify location on disk
    // Write the file data to disk
    // TODO: Place restrictions on upload data
    disk = new File( “C:\\”+item.getName() );
    log.info(”am after disk”);
    item.write( disk );

    // Return an XML node with the file name and size (in bytes)
    out.println( “” );
    }
    }

    // Close off the response XML data and stream
    out.println( “” );
    out.close();
    // Rudimentary handling of any exceptions
    // TODO: Something useful if an error occurs
    } catch( FileUploadException fue ) {
    fue.printStackTrace();
    } catch( IOException ioe ) {
    log.info(”io error”);
    ioe.printStackTrace();
    } catch( Exception e ) {
    e.printStackTrace();
    }
    }

    }

    web.xml
    ………

    XFireServlet
    org.codehaus.xfire.transport.http.XFireConfigurableServlet

    XFireServlet
    /servlet/XFireServlet/*

    XFireServlet
    /services/*

    FileServlet
    com.boa.flex.servlet.UploadFileServlet

    FileServlet
    /action/*

  13. baji Says:

    here is my mxml file

  14. Ed LaFave Says:

    Raj, take a look at the FileReferenceList class for uploading multiple files.

  15. ashok Says:

    thank you. thank you and thank you once again. i have been literally breaking my head over how does this work, and have tried for two days now, and now i find this.

    the web, open source would not have been as amazing, if it would not have been for people like you.

  16. Nikhil Says:

    I am trying to upload a file using flex3 from mozilla browser to a servlet. I am getting the following error:
    Error #2044: Unhandled IOErrorEvent: text=Error #2038: File I/O error.

    The request never reaches the server.

    I even tried to run the source code provided by you but get the same error. Is this a know bug in Flex 3? Or could this be happening because of Firefox/flash plugin I am using.

    Firefox version - 2.0.0.6-25
    Flash plugin - 9.0.115.0-16

    Any help in this regard will be highly appericiated.

    Thanks,

    Nikhil

  17. Chesterfield Sofas Says:

    I never fail to be impressed by your intuitive articles and this one is no exception.

    Thanks.

  18. Mark Says:

    WOW..Thanks for the complete tutorial!

  19. Russian girl Says:

    Very interesting and exciting.
    Thanks so much for this post, I’ve been looking all over for possible methods of uploading using java.

  20. Simon G. Says:

    Very nice article about Flex to Java Servlet File Upload and very expressed tutorial. It is really very useful for me, thanks!

    Simon G.

  21. mores Says:

    You should also mention how to maintain session. Here is a good link:

    http://www.kahunaburger.com/2007/10/31/flex-uploads-via-httphttps/

  22. Tomelloso Says:

    Thanks for this useful post, I’ve been looking all over for this and now I find and solve my problem. Thanks.

  23. Jonathan Says:

    Thanks for code, but

    Error #2038: File I/o Error URL:http://localhost:8080/mywebsite/action/UploadServlet.

    Why?

    You have the solution

    please

  24. Zurvita Says:

    This is absolutely amazing stuff!! REading through this post I am amazed at the work it takes just to write the post.
    Wow!! Thanks again Kevin for giving us great information.

  25. LakshmikanthReddy Says:

    hi kevin ,

    Thanks a lot and lot and lot , i cannot express my happiness once after having looked at u r work , but here i got struck with page load error ie., “connection interrupted” , i think i am not specifying the correctly and action attribute of form tag , if possible can u explain me what should be written in those two places exactly and clearly .

    Thank u .

Leave a Reply