Spring 3 File Upload Example

I had the opportunity to figure out how to do file uploads using Spring 3 the other day and I couldn't find anything that pulled it all together. What follows is a complete example of how to do MVC based file uploads with Spring 3.

I'm going to assume you know something about Spring and their MVC configuration in general. If you want a simple MVC example to start with check out their SVN MVC-Basic sample. There is a decent amount of boiler plate work so I've created a project zip file with all the code, a build file and configuration in it (you just need to add the libraries).

First lets start by gathering up all the libraries we are going to need (see the end of the post for the directory layout I used or just unzip the project). Grab a copy of the Spring 3 libraries, at this time the latest version is spring-framework-3.0.1.RELEASE-A.zip and that is what I used for the following example. For the file upload part there are two non-Spring dependencies as well: Apache Commons FileUpload and Apache Commons IO. If you want to use the example project from the zip just copy all the jar files to the lib directory.

Next it is worth a quick look at the information provided in the Spring documentation about MVC multipart. It touches on what needs to be done but leaves out a full example. In documentation you will see that they talk about using a "multipart resolver" and that can be found at the end of web/WEB-INF/spring/app-config.xml:

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
		http://www.springframework.org/schema/beans	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- Scans the classpath of this application for @Components to deploy as beans -->
    <context:component-scan base-package="net.ioncannon"/>

    <!-- Configures Spring MVC -->
    <import resource="mvc-config.xml"/>

    <!-- Configure the multipart resolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- one of the properties available; the maximum file size in bytes -->
        <property name="maxUploadSize" value="100000"/>
    </bean>

</beans>

The above app-config.xml configuration file is referenced from the mvc-config.xml configuration file. The mvc-config.xml configuration file doesn't need anything special for multipart uploads so I'll skip listing it here, have a look in the zip file if you are interested in its contents.

Now that the configuration is set the next step is to create the entry form for the upload. I've done this in the view JSP found in web/WEB-INF/views/upload/uploadForm.jsp:

<%@page contentType="text/html;charset=UTF-8" %>
<%@page pageEncoding="UTF-8" %>
<%@ page session="false" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<html>
    <head>
        <META http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>Upload Example</title>
    </head>
    <body>
        <form:form modelAttribute="uploadItem" method="post" enctype="multipart/form-data">
            <fieldset>
                <legend>Upload Fields</legend>

                <p>
                    <form:label for="name" path="name">Name</form:label><br/>
                    <form:input path="name"/>
                </p>

                <p>
                    <form:label for="fileData" path="fileData">File</form:label><br/>
                    <form:input path="fileData" type="file"/>
                </p>

                <p>
                    <input type="submit" />
                </p>

            </fieldset>
        </form:form>
    </body>
</html>

A few notes about this view JSP:

  • The form needs to have the encoding type set correctly. Look for: enctype="multipart/form-data"
  • The file input field needs to be set: type="file"
  • In the above I've included a Name field in the model as well as the File field just to show that you can mix fields in the same form
  • The definition of the model can be found next and I assume that it is introduced into the form as "uploadItem"

The model is pretty simple and can be found in src/net/ioncannon/model/UploadItem.java:

package net.ioncannon.model;

import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class UploadItem
{
  private String name;
  private CommonsMultipartFile fileData;

  public String getName()
  {
    return name;
  }

  public void setName(String name)
  {
    this.name = name;
  }

  public CommonsMultipartFile getFileData()
  {
    return fileData;
  }

  public void setFileData(CommonsMultipartFile fileData)
  {
    this.fileData = fileData;
  }
}

The Name attribute is just an extra input field and not the name of the file. Notice that the File attribute is of type CommonsMultipartFile. The CommonsMultipartFile type has a number of features that give you information about the uploaded file as well as access to its contents.

The controller brings everything together. The source can be found in the file src/net/ioncannon/controller/UploadController.java:

package net.ioncannon.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;

import net.ioncannon.model.UploadItem;

@Controller
@RequestMapping(value = "/upload")
public class UploadController
{
  @RequestMapping(method = RequestMethod.GET)
  public String getUploadForm(Model model)
  {
    model.addAttribute(new UploadItem());
    return "upload/uploadForm";
  }

  @RequestMapping(method = RequestMethod.POST)
  public String create(UploadItem uploadItem, BindingResult result)
  {
    if (result.hasErrors())
    {
      for(ObjectError error : result.getAllErrors())
      {
        System.err.println("Error: " + error.getCode() +  " - " + error.getDefaultMessage());
      }
      return "upload/uploadForm";
    }

    // Some type of file processing...
    System.err.println("-------------------------------------------");
    System.err.println("Test upload: " + uploadItem.getName());
    System.err.println("Test upload: " + uploadItem.getFileData().getOriginalFilename());
    System.err.println("-------------------------------------------");

    return "redirect:/app/";
  }
}

Once the file is uploaded I'm just dumping out part of the information. Doing something exciting with the file is up to you.

That is all there is to it. Here is a list of what the project structure looks like with everything pulled together including all the libraries, build file, source and configuration files:

build/build.xml
lib/commons-fileupload-1.2.1.jar
lib/commons-io-1.4.jar
lib/org.springframework.aop-3.0.1.RELEASE-A.jar
lib/org.springframework.asm-3.0.1.RELEASE-A.jar
lib/org.springframework.aspects-3.0.1.RELEASE-A.jar
lib/org.springframework.beans-3.0.1.RELEASE-A.jar
lib/org.springframework.context-3.0.1.RELEASE-A.jar
lib/org.springframework.context.support-3.0.1.RELEASE-A.jar
lib/org.springframework.core-3.0.1.RELEASE-A.jar
lib/org.springframework.expression-3.0.1.RELEASE-A.jar
lib/org.springframework.instrument-3.0.1.RELEASE-A.jar
lib/org.springframework.instrument.tomcat-3.0.1.RELEASE-A.jar
lib/org.springframework.jdbc-3.0.1.RELEASE-A.jar
lib/org.springframework.jms-3.0.1.RELEASE-A.jar
lib/org.springframework.orm-3.0.1.RELEASE-A.jar
lib/org.springframework.oxm-3.0.1.RELEASE-A.jar
lib/org.springframework.spring-library-3.0.1.RELEASE-A.libd
lib/org.springframework.test-3.0.1.RELEASE-A.jar
lib/org.springframework.transaction-3.0.1.RELEASE-A.jar
lib/org.springframework.web-3.0.1.RELEASE-A.jar
lib/org.springframework.web.portlet-3.0.1.RELEASE-A.jar
lib/org.springframework.web.servlet-3.0.1.RELEASE-A.jar
lib/org.springframework.web.struts-3.0.1.RELEASE-A.jar
src/net/ioncannon/controller/UploadController.java
src/net/ioncannon/model/UploadItem.java
web/WEB-INF/web.xml
web/WEB-INF/spring/app-config.xml
web/WEB-INF/spring/mvc-config.xml
web/WEB-INF/views/welcome.jsp
web/WEB-INF/views/upload/uploadForm.jsp

Leave a Reply

Your email address will not be published.