Spring's built-in multipart support handles file uploads in web
applications. You enable this multipart support with pluggable
MultipartResolver
objects, defined in the
org.springframework.web.multipart
package. Out
of the box, Spring provides a
MultipartResolver
for use with
Commons FileUpload (http://jakarta.apache.org/commons/fileupload). How
uploading files is supported will be described in the rest of this
chapter.
By default, Spring does no multipart handling, because some
developers want to handle multiparts themselves. You enable Spring
multipart handling by adding a multipart resolver to the web
application's context. Each request is inspected to see if it contains a
multipart. If no multipart is found, the request continues as expected.
If a multipart is found in the request, the
MultipartResolver
that has been declared in your
context is used. After that, the multipart attribute in your request is
treated like any other attribute.
The following example shows how to use the
CommonsMultipartResolver
:
<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>
This example uses the
CosMultipartResolver
:
<bean id="multipartResolver" class="org.springframework.web.multipart.cos.CosMultipartResolver"> <!-- one of the properties available; the maximum file size in bytes --> <property name="maxUploadSize" value="100000"/> </bean>
Of course you also need to put the appropriate jars in your
classpath for the multipart resolver to work. In the case of the
CommonsMultipartResolver
, you need to use
commons-fileupload.jar
; in the case of the
CosMultipartResolver
, use
cos.jar
.
When the Spring DispatcherServlet
detects a
multi-part request, it activates the resolver that has been declared in
your context and hands over the request. The resolver then wraps the
current HttpServletRequest
into a
MultipartHttpServletRequest
that supports
multipart file uploads. Using the
MultipartHttpServletRequest
you can get
information about the multiparts contained by this request and actually
get access to the multipart files themselves in your controllers.
After the MultipartResolver
completes its
job, the request is processed like any other. To use it,
you create a form with an upload field (see immediately below) that will
allow the user to upload a form, then let Spring bind the file onto your
form (backing object).
<html> <head> <title>Upload a file please</title> </head> <body> <h1>Please upload a file</h1> <form method="post" action="upload.form" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit"/> </form> </body> </html>
As you can see, we've created a field named after the property of
the bean that holds the byte[]
. The
encoding attribute (enctype="multipart/form-data"
)
lets the browser know how to encode the multipart fields.
As with any property that is not automatically convertible
to a string or primitive type, you must register a custom editor with
the ServletRequestDatabinder
to be able to put
binary data in your objects. Two editors can handle files and set the
results on an object. A StringMultipartEditor
can
convert files to Strings (using a user-defined character set), and a
ByteArrayMultipartEditor
converts files to byte
arrays. They function just as the
CustomDateEditor
does.
So, to be able to upload files using an HTML form, declare the resolver, a url mapping to a controller that will process the bean, and the controller itself:
<beans> <!-- lets use the Commons-based implementation of the MultipartResolver interface --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <value> /upload.form=fileUploadController </value> </property> </bean> <bean id="fileUploadController" class="examples.FileUploadController"> <property name="commandClass" value="examples.FileUploadBean"/> <property name="formView" value="fileuploadform"/> <property name="successView" value="confirmation"/> </bean> </beans>
After that, create the controller and the actual class to hold the file property:
public class FileUploadController extends SimpleFormController { protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws ServletException, IOException { // cast the bean FileUploadBean bean = (FileUploadBean) command; let's see if there's content there byte[] file = bean.getFile(); if (file == null) { // hmm, that's strange, the user did not upload anything } // well, let's do nothing with the bean for now and return return super.onSubmit(request, response, command, errors); } protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws ServletException { // to actually be able to convert Multipart instance to byte[] // we have to register a custom editor binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor()); // now Spring knows how to handle multipart object and convert them } } public class FileUploadBean { private byte[] file; public void setFile(byte[] file) { this.file = file; } public byte[] getFile() { return file; } }
As you can see, the FileUploadBean
has a
property typed byte[]
that holds the file. The
controller registers a custom editor to let Spring know how to convert
the multipart objects the resolver has found to properties specified by
the bean. In this example, nothing is done with the
byte[]
property of the bean itself, but in practice
you can do save it in a database, mail it to somebody, and so on.
The following is an equivalent example in which a file is bound straight to a String-typed property on a (form backing) object:
public class FileUploadController extends SimpleFormController { protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws ServletException, IOException { // cast the bean FileUploadBean bean = (FileUploadBean) command; let's see if there's content there String file = bean.getFile(); if (file == null) { // hmm, that's strange, the user did not upload anything } // well, let's do nothing with the bean for now and return return super.onSubmit(request, response, command, errors); } protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws ServletException { // to actually be able to convert Multipart instance to a String // we have to register a custom editor binder.registerCustomEditor(String.class, new StringMultipartFileEditor()); // now Spring knows how to handle multipart object and convert them } } public class FileUploadBean { private String file; public void setFile(String file) { this.file = file; } public String getFile() { return file; } }
The preceding example only makes (logical) sense in the context of uploading a plain text file. It would not work as well with an image file upload.
The third (and final) option is where one binds directly to a
MultipartFile
property declared on the
(form backing) object's class. In this case one does not need to
register any custom PropertyEditor
because there is no type conversion to be performed.
public class FileUploadController extends SimpleFormController { protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws ServletException, IOException { // cast the bean FileUploadBean bean = (FileUploadBean) command; let's see if there's content there MultipartFile file = bean.getFile(); if (file == null) { // hmm, that's strange, the user did not upload anything } // well, let's do nothing with the bean for now and return return super.onSubmit(request, response, command, errors); } } public class FileUploadBean { private MultipartFile file; public void setFile(MultipartFile file) { this.file = file; } public MultipartFile getFile() { return file; } }