34. Implementing File Upload for Spring MVC

PROBLEM

Some Spring MVC applications have requirements to store file-based resources in a database, and often these application needs a facility for uploading resources (i.e. images and documents) from a web-based user interface.

SOLUTION

The HTML FORM and INPUT elements are used to implement the user interface for uploading files. In an HTML form the ENCTYPE parameter determines how the form data is encoded, and for uploading files the value "multipart/form-data" should be used. For the INPUT element the type should be set to "file". While standard HTML works just fine, the Skyway tag library (Open Source: Apache License) includes a specialized file upload web control.

With the user interface addressed by HTML and/or the Skyway tag library, the next component to address is the backend logic. The Spring MVC application needs to be setup to handle the multipart data that is being sent from the UI. Fortunately Spring MVC has support for this in the form of MultiPartResolver and ByteArrayMultipartFileEditor. In addition to bootstrapping a lof of the necessary Spring configuration to support file uploading, Skyway Builder also includes a custom resolver (Open Source: Apache License) that makes it easier to bind the file attributes (filename, file size, content type) to your domain model.

HOW IT WORKS

As mentioned earlier the first step is to implement the user interface for uploading content, and the following list describe the details.

Implementing the file upload user interface

  1. Update the ENCTYPE of the form to "multipart/form-data". This can be done in a form implemented using the standard HTML FORM tag, the Spring Form tag, or the Skyway Form tag. [REQUIRED]

  2. Add an HTML INPUT element with the TYPE attribute set to "file", and set the NAME attribute to the field on your domain object (ModelAttribute) where the uploaded file should be stored. Please note that the domain object itself is specified by the ModelAttribute parameter on the Spring Form or Skyway Builder form tags. [REQUIRED]

  3. Add one or more hidden form elements directing the backend MultiPartResolver to store the filename, the content type, and/or the file size in the domain object. The NAME must configured with a reference to the name of the HTML INPUT element in step #2 and a suffix corresponding to the file attribute. The VALUE must be configured with the field on the domain object that should be set. Please note that this step is only required if you also want to store the filename, the content type, and/or the file size in your domain model. [OPTIONAL]

Table 2.5. File Upload Suffixes

SuffixDescription
_contentTypeVarReference to the file content type
_fileNameVarReference to the filename
_sizeVarReference to the file size

This following JSP fragment shows a typical file upload implementation using standard HTML, and it includes the binding of file attributes to the domain model.

Example 2.38. File Upload - HTML

<form:form action="${pageContext.request.contextPath}/savePhoto.html" 
           method="POST" enctype="multipart/form-data"1 modelAttribute="photo"2>
   <input id="content" name="content" type="file"/>3
   <input type="hidden" name="content_contentTypeVar" value="contentType"/>4
   <input type="hidden" name="content_fileNameVar" value="filename"/>5
   <input type="hidden" name="content_sizeVar" value="contentSize"/>6
   <input type="submit"/>
</form:form>  

1

The encoding type is set to "multipart/form-data"

2

The ModelAttribute is set to "photo". This is the object that will contain the file (byte array), filename, file size and content type for the uploaded file.

3

This input html element will let the end-user select a file from their filesystem to upload. The file is bound to the content field (photo.content). In Skyway Builder this field is defined as a Large Data Storage type.

4

This input html element will bind the content type to the contentType field (photo.contentType). In Skyway Builder this field is defined as a Text (String) type.

5

This input html element will bind the file name to the filename field (photo.filename). In Skyway Builder this field is defined as a Text (String) type.

6

This input html element will bind the file size to the contentSize field (photo.contentSize). In Skyway Builder this field is defined as a Integer type.

The following JSP fragment shows a file upload implementation using the File Upload web control from the Skyway TagLib. The html rendered the file upload web control will render the HTML described previously.

Example 2.39. File Upload - Upload Web Control (Skyway TagLib)

<form:form action="${pageContext.request.contextPath}/savePhoto.html" 
           method="POST" enctype="multipart/form-data"1 modelAttribute="photo"2>
   <skyway:binaryUpload controller="" designPath="" path="content" 
                        contentTypeBinding="contentType" 
                        fileNameBinding="filename" 
                        sizeBinding="contentSize">3
   </skyway:binaryUpload>
   <input type="submit"/>
</form:form>  

1

The encoding type is set to "multipart/form-data"

2

The ModelAttribute is set to "photo". This is the object that will contain the file, filename, file size and content type for the uploaded file.

3

The JSP tag will emit the html for storing the file, filename, file size and content type into the respective fields on the photo modelAttribute.

Skyway Builder already bootstraps the Spring MVC application to support file uploads, so there is zero configuration required by the developer. The following list describes the relevant configurations that are automatically bootstrapped by Skyway Builder.

Bootstrapping of File Upload Support

  1. A multiPartResolver is registered. See the generated web context file (projectName-generated-web-context.xml).

  2. A ByteArrayMultipartFileEditor property editor is registered. See the initBinder() method in a scaffolded or generated controller.

The only responsibility of the developer is to implement a request handler (Controller Operation) that accepts the domain object as an input. The input variable should match the ModelAttribute parameter that was specified in the Spring or Skyway Form tag. Typically you will implement the backend first, and then develop the UI that binds data to the backend. When the end-user of the application posts a form to the request handler, the file is stored in the domain object field specified by the html (i.e. photo.content). The size, type, and filename are optionally stored in the domain object fields specified by the html, if the optional hidden form fields are included.

RELATED RECIPES

  1. Implementing File Upload for Spring Web Flow

  2. Streaming binary content