The framework comes with built in file upload support. Uploading a file is simple. When FilterDispatcher receives a request, it checks to see if the request contains multipart content. If it does the dispatcher creates a MultipartWrapperRequest. This wrapper handles receiving the file and saving to disk. It is important for the Action programmer to check to see if any errors occured during processing. Three properties can be set that effect file uploading.

Ensure you have the necessary file upload libraries in your application. If using the default file upload parser, Commons Fileupload and its dependencies should be in your application's classpath.

Properties

Properties can be set by putting a struts.properties file in WEB-INF/classes. Any property found in the properties file will override the default value.

  1. struts.multipart.parser - This property should be set to a class that extends MultiPartRequest. Currently, the framework ships with the Jakarta FileUpload implementation.
  2. struts.multipart.saveDir - The directory where the uploaded files will be placed. If this property is not set it defaults to javax.servlet.context.tempdir.
  3. struts.multipart.maxSize - The maximum file size in bytes to allow for upload. This helps prevent system abuse by someone uploading lots of large files. The default value is 2 Megabytes and can be set as high as 2 Gigabytes (higher if you want to edit the Pell multipart source but you really need to rethink things if you need to upload files larger then 2 Gigabytes!) If you are uploading more than one file on a form the maxSize applies to the combined total, not the individual file sizes.

If you're happy with the defaults, there is no need to put any of the properties in struts.properties.

struts.properties
# put the uploaded files in /tmp. My application will move them to their
# final destination
struts.multipart.saveDir=/tmp

Note, while you can set these properties to new values at runtime the MultiPartRequestWrapper is created and the file handled before your Action code is called. So if you want to change values you must do so before this Action.

Sample Form

<%@ taglib uri="action2" prefix="s" %>

<html>
  <head>
   <title>File Upload Test</title>
  </head>
  <body>
    <h1>File Upload</h1>

    <form action="FileUpload.action" method="POST" enctype="multipart/form-data">

    <center>
      <table width="350" border="0" cellpadding="3" cellspacing="0">
      <tr>
        <td colspan="2"><input type="file" name="FileName" value="Browse..." size="50"/></td>
      </tr>
      <tr>
        <td colspan="2" align="center">
          <input type="submit" value="Submit">
        </td>
      </tr>
      </table>
    </center>
  </form>
</body>
</html>

That's all you have to do to upload a file. No coding required, the file will be placed in the default directory. However, that leaves us with no error checking among other things. So let's add some code to the Action.

File Upload Action

Before the Action method is called the dispatcher will upload the file. Then we can get access to information about the file from MultiPartRequestWrapper.

FileUploadAction.java
MultiPartRequestWrapper multiWrapper =
		(MultiPartRequestWrapper) ServletActionContext.getRequest();

The first thing you should always do is check for errors. If there were any, there's no point in continuing, most methods will return null. Unfortunately, currently there is no easy way to distinguish what error occured making it more difficult to route to different error pages.

if (multiWrapper.hasErrors()) {
  Collection errors = multiWrapper.getErrors();
  Iterator i = errors.iterator();
  while (i.hasNext()) {
    addActionError((String) i.next());
  }
  return ERROR;
}

Now get the input tag name for the uploaded file and use that to get information on the transfer. Since you can upload multiple files (just add multiple input tags) at a time getFileNames returns an Enumeration of the names.

Enumeration e = multiWrapper.getFileNames();

while (e.hasMoreElements()) {
   // get the value of this input tag
   String inputValue = (String) e.nextElement();

   // get the content type
   String contentType = multiWrapper.getContentType(inputValue);

   // get the name of the file from the input tag
   String fileName = multiWrapper.getFilesystemName(inputValue);

   // Get a File object for the uploaded File
   File file = multiWrapper.getFile(inputValue);

   // If it's null the upload failed
   if (file == null) {
      addActionError("Error uploading: " + multiWrapper.getFilesystemName(inputValue));
   }

   // Do additional processing/logging...
}

Further Improvements

Code above may be packed into one nice reusable component (Interceptor) that handles 90% of all typical file upload tasks. And Action does not know anything about web-app and just gets its files. Neat.

(lightbulb) For more, see the File Upload Interceptor

  • No labels

7 Comments

  1. Anonymous

    Thanks Tracy for the great helpful work!

    I think it would be clearer if explicitly mention the name of the properties file where the 3 settings for the multi-part upload are set, specially crafted for newbies (smile)

    Also there is a spelling mistake on the first paragraph, where it says MutlipartWrapperRequest.

  2. Unknown User (robertdouglass)

    The FileUpload.java class should appear in full here.

    It is not clear to the newbie that the action must implement com.opensymphony.xwork.ValidationAware;

  3. Anonymous

    File upload is broken now. There is a bug in com.opensymphony.webwork.dispatcher.ServletDispatcher class.

    Before this revision upload was ok:
    ---------------------------
    Revision : 1.12
    Date : 2003/10/6 2:52:5
    Author : 'cameronbraid'
    State : 'Exp'
    Lines : +3 -5
    Description :
    fixed bug introduced when refactoring
    ---------------------------

    but in this revision new bug added and request no more wrapped before passing to serviceAction() method. Fix it, please!

  4. Anonymous

    It seems that webwork will upload multipart content automatically before action execute.

    How to rename the filename of the uploading file before actually uploaded?

  5. Unknown User (callmeharry)

    Wooo Thanks this is works to upload file
    But...
    How can i delete the file i've been uploaded ?

  6. Unknown User (stchauvin)

    WebWork 2.1.7 supports the Multipart request from Jakarta. Configure your 'webwork.properties':

    webwork.multipart.parser = cos
    -> com.opensymphony.webwork.dispatcher.multipart.CosMultiPartRequest

    webwork.multipart.parser = pell
    -> com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest

    webwork.multipart.parser = jakarta
    -> com.opensymphony.webwork.dispatcher.multipart.JakartaMultiPartRequest

    The 'commons-fileupload.jar' library is included in the core of the WW distribution.

  7. We should explicitly list the dependencies for those not using Maven.

    They are
    commons-fileupload-1.1.1.jar
    commons-io-1.1.jar

    These dependencies should also be in the /lib directory