In this post we will implement Single and Multiple Fileupload functionality using Spring MultipartResolver. Spring provides build-in multipart support to handle file uploads in a web application. Let’s get going.
- Spring Boot+AngularJS+Spring Data+Hibernate+MySQL CRUD App
- Secure Spring REST API using OAuth2
- Spring Boot REST API Tutorial
- Spring Boot WAR deployment example
- Spring Boot Introduction + Hello World Example
- AngularJS+Spring Security using Basic Authentication
- Secure Spring REST API using Basic Authentication
- Spring 4 Caching Annotations Tutorial
- Spring 4 Cache Tutorial with EhCache
- Spring 4 MVC+JPA2+Hibernate Many-to-many Example
- Spring 4 Email Template Library Example
- Spring 4 Email With Attachment Tutorial
- Spring MVC 4+JMS+ActiveMQ Integration Example
- Spring 4 Email Integration Tutorial
- Spring 4+JMS+ActiveMQ @JmsLister @EnableJms Example
- Spring 4+JMS+ActiveMQ Integration Example
- Spring MVC 4+Spring Security 4 + Hibernate Integration Example
- Spring MVC 4+AngularJS Example
- Spring MVC 4+AngularJS Server communication example : CRUD application using ngResource $resource service
- Spring MVC 4+AngularJS Routing with UI-Router Example
- Spring MVC 4+AngularJS Routing with ngRoute Example
- Spring MVC4 FileUpload-Download Hibernate+MySQL Example
- Spring MVC 4 File Upload Example using Servlet 3 MultiPartConfigElement
- Spring MVC 4 File Download Example
Short Overview
Spring provides file upload support using MultiPartResolver
interface and provides two out-of-box implementations for that.
-
1. To use with Apache Commons . Spring
CommonsMultipartResolver
is a MultipartResolver implementation for use with Apache Commons FileUpload. It requires apache commons-fileupload.jar to be present on classpath. It’s not specific to Servlet 3 environment but it works equally well with Servlet 3.x containers.<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
-
2. To use with Servlet 3.0 multipart request. Depends on which setup you are using[XML or JavaConfig].
For XML setup, you need to mark the DispatcherServlet with a
"multipart-config"
section in web.xml.
For Annoataion/JavaConfig setup, registeringjavax.servlet.MultipartConfigElement
with DispatcherServlet. OR using@MultipartConfig
on a custom servlet.
This post focuses only on CommonsMultipartResolver . Next post shows same example using Servlet 3.0 specific implementations.
Basically we need to do following :
- Create a Bean of Type CommonsMultipartResolver , specifying few properties related to file uploading.
- Include Apache Commons commons-fileupload.jar in classpath.
- Form which contains file upload functionality should specify enctype attribute with multipart content [enctype=”multipart/form-data”]
- To handle file input, input type must be ‘file’
Something like this:
<form method="POST" enctype="multipart/form-data" > .... <input type="file" id="file" /> .... <input type="submit" value="Upload"> </form>
Complete Example is discussed below.
Complete Example
Following technologies being used:
- Spring 4.2.0.RELEASE
- Apache Commons fille-upload 1.3.1
- validation-api 1.1.0.Final
- Bootstrap v3.3.2
- Maven 3
- JDK 1.7
- Tomcat 8.0.21
- Eclipse JUNO Service Release 2
Let’s begin.
Project Structure
Declare Dependencies in pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.websystique.springmvc</groupId> <artifactId>Spring4MVCFileUploadCommonsExample</artifactId> <packaging>war</packaging> <version>1.0.0</version> <name>Spring4MVCFileUploadCommonsExample Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <springframework.version>4.2.0.RELEASE</springframework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- For user input validation --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <warSourceDirectory>src/main/webapp</warSourceDirectory> <warName>Spring4MVCFileUploadCommonsExample</warName> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </pluginManagement> <finalName>Spring4MVCFileUploadCommonsExample</finalName> </build> </project>
Create Configuration Class
package com.websystique.springmvc.configuration; import java.io.IOException; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.websystique.springmvc") public class HelloWorldConfiguration extends WebMvcConfigurerAdapter{ @Bean(name="multipartResolver") public CommonsMultipartResolver getResolver() throws IOException{ CommonsMultipartResolver resolver = new CommonsMultipartResolver(); //Set the maximum allowed size (in bytes) for each individual file. resolver.setMaxUploadSizePerFile(5242880);//5MB //You may also set other available properties. return resolver; } @Override public void configureViewResolvers(ViewResolverRegistry registry) { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); registry.viewResolver(viewResolver); } @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("/static/"); } }
Highlight of this Configuration class is CommonsMultipartResolver Bean. It’s a MultipartResolver implementation for Apache Commons FileUpload. You can set properties like max filesize, size Threshold, headerEncoding etc. In our case we have just specified the max allowed file size in bytes (set to 5 MB).
This Configuration class in XML format will be:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.websystique.springmvc" /> <mvc:annotation-driven /> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- one of the several properties available; the maximum file size in bytes --> <property name="maxUploadSizePerFile" value="5242880"/> </bean> <mvc:resources mapping="/static/**" location="/static/" /> <mvc:default-servlet-handler /> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename"> <value>messages</value> </property> </bean> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/views/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> </beans>
Create Model classes
Spring provides org.springframework.web.multipart.MultipartFile
which is a representation of an uploaded file received in a multipart request. It provides handy methods like getName(), getContentType(), getBytes(), getInputStream() etc.. which make life bit easier while retrieving information about file being uploaded.
Let’s write a wrapper class to further simply it’s usage in our application
package com.websystique.springmvc.model; import org.springframework.web.multipart.MultipartFile; public class FileBucket { MultipartFile file; public MultipartFile getFile() { return file; } public void setFile(MultipartFile file) { this.file = file; } }
To demonstrate Multiple uploads example as well, let’s create one more wrapper class.
package com.websystique.springmvc.model; import java.util.ArrayList; import java.util.List; public class MultiFileBucket { List<FileBucket> files = new ArrayList<FileBucket>(); public MultiFileBucket(){ files.add(new FileBucket()); files.add(new FileBucket()); files.add(new FileBucket()); } public List<FileBucket> getFiles() { return files; } public void setFiles(List<FileBucket> files) { this.files = files; } }
This class can handle up to 3 file uploads.
Create Controller class
package com.websystique.springmvc.controller; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.util.FileCopyUtils; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.multipart.MultipartFile; import com.websystique.springmvc.model.FileBucket; import com.websystique.springmvc.model.MultiFileBucket; import com.websystique.springmvc.util.FileValidator; import com.websystique.springmvc.util.MultiFileValidator; @Controller public class FileUploadController { private static String UPLOAD_LOCATION="C:/mytemp/"; @Autowired FileValidator fileValidator; @Autowired MultiFileValidator multiFileValidator; @InitBinder("fileBucket") protected void initBinderFileBucket(WebDataBinder binder) { binder.setValidator(fileValidator); } @InitBinder("multiFileBucket") protected void initBinderMultiFileBucket(WebDataBinder binder) { binder.setValidator(multiFileValidator); } @RequestMapping(value={"/","/welcome"}, method = RequestMethod.GET) public String getHomePage(ModelMap model) { return "welcome"; } @RequestMapping(value="/singleUpload", method = RequestMethod.GET) public String getSingleUploadPage(ModelMap model) { FileBucket fileModel = new FileBucket(); model.addAttribute("fileBucket", fileModel); return "singleFileUploader"; } @RequestMapping(value="/singleUpload", method = RequestMethod.POST) public String singleFileUpload(@Valid FileBucket fileBucket, BindingResult result, ModelMap model) throws IOException { if (result.hasErrors()) { System.out.println("validation errors"); return "singleFileUploader"; } else { System.out.println("Fetching file"); MultipartFile multipartFile = fileBucket.getFile(); //Now do something with file... FileCopyUtils.copy(fileBucket.getFile().getBytes(), new File(UPLOAD_LOCATION + fileBucket.getFile().getOriginalFilename())); String fileName = multipartFile.getOriginalFilename(); model.addAttribute("fileName", fileName); return "success"; } } @RequestMapping(value="/multiUpload", method = RequestMethod.GET) public String getMultiUploadPage(ModelMap model) { MultiFileBucket filesModel = new MultiFileBucket(); model.addAttribute("multiFileBucket", filesModel); return "multiFileUploader"; } @RequestMapping(value="/multiUpload", method = RequestMethod.POST) public String multiFileUpload(@Valid MultiFileBucket multiFileBucket, BindingResult result, ModelMap model) throws IOException { if (result.hasErrors()) { System.out.println("validation errors in multi upload"); return "multiFileUploader"; } else { System.out.println("Fetching files"); List<String> fileNames= new ArrayList<String>(); //Now do something with file... for(FileBucket bucket : multiFileBucket.getFiles()){ FileCopyUtils.copy(bucket.getFile().getBytes(), new File(UPLOAD_LOCATION + bucket.getFile().getOriginalFilename())); fileNames.add(bucket.getFile().getOriginalFilename()); } model.addAttribute("fileNames", fileNames); return "multiSuccess"; } } }
Above controller is fairly trivial. It handles GET and POST request for file upload view. Once file is selected from File picker and user clicked on upload, we are simply creating a new file with the same name and bytes content as original file, copying the bytes from original file. For that we are using Spring FileCopyUtils
utility class to copy stream from source to destination. In this example, we have specified destination as C:/mytemp folder, all files will end up in this folder.
Create Validators classes
We are using some Validators to verify that user have indeed selected a file to be uploaded. They are shown below.
package com.websystique.springmvc.util; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import com.websystique.springmvc.model.FileBucket; @Component public class FileValidator implements Validator { public boolean supports(Class<?> clazz) { return FileBucket.class.isAssignableFrom(clazz); } public void validate(Object obj, Errors errors) { FileBucket file = (FileBucket) obj; if(file.getFile()!=null){ if (file.getFile().getSize() == 0) { errors.rejectValue("file", "missing.file"); } } } }
package com.websystique.springmvc.util; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import com.websystique.springmvc.model.FileBucket; import com.websystique.springmvc.model.MultiFileBucket; @Component public class MultiFileValidator implements Validator { public boolean supports(Class<?> clazz) { return MultiFileBucket.class.isAssignableFrom(clazz); } public void validate(Object obj, Errors errors) { MultiFileBucket multiBucket = (MultiFileBucket) obj; int index=0; for(FileBucket file : multiBucket.getFiles()){ if(file.getFile()!=null){ if (file.getFile().getSize() == 0) { errors.rejectValue("files["+index+"].file", "missing.file"); } } index++; } } }
messages.properties
missing.file= Please select a file.
Create Views
singleFileUploader.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Spring 4 MVC File Upload Example</title> <link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet" type="text/css"></link> <link href="<c:url value='/static/css/app.css' />" rel="stylesheet" type="text/css"></link> </head> <body> <div class="form-container"> <h1>Spring 4 MVC File Upload Example </h1> <form:form method="POST" modelAttribute="fileBucket" enctype="multipart/form-data" class="form-horizontal"> <div class="row"> <div class="form-group col-md-12"> <label class="col-md-3 control-lable" for="file">Upload a file</label> <div class="col-md-7"> <form:input type="file" path="file" id="file" class="form-control input-sm"/> <div class="has-error"> <form:errors path="file" class="help-inline"/> </div> </div> </div> </div> <div class="row"> <div class="form-actions floatRight"> <input type="submit" value="Upload" class="btn btn-primary btn-sm"> </div> </div> </form:form> <a href="<c:url value='/welcome' />">Home</a> </div> </body> </html>
success.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>File Upload Success</title> <link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet"></link> <link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link> </head> <body> <div class="success"> File <strong>${fileName}</strong> uploaded successfully. <br/><br/> <a href="<c:url value='/welcome' />">Home</a> </div> </body> </html>
multiFileUploader.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Spring 4 MVC File Multi Upload Example</title> <link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet" type="text/css"></link> <link href="<c:url value='/static/css/app.css' />" rel="stylesheet" type="text/css"></link> </head> <body> <div class="form-container"> <h1>Spring 4 MVC Multi File Upload Example </h1> <form:form method="POST" modelAttribute="multiFileBucket" enctype="multipart/form-data" class="form-horizontal"> <c:forEach var="v" varStatus="vs" items="${multiFileBucket.files}"> <form:input type="file" path="files[${vs.index}].file" id="files[${vs.index}].file" class="form-control input-sm"/> <div class="has-error"> <form:errors path="files[${vs.index}].file" class="help-inline"/> </div> </c:forEach> <br/> <div class="row"> <div class="form-actions floatRight"> <input type="submit" value="Upload" class="btn btn-primary btn-sm"> </div> </div> </form:form> <br/> <a href="<c:url value='/welcome' />">Home</a> </div> </body> </html>
multiSuccess.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>File Upload Success</title> <link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet"></link> <link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link> </head> <body> <div class="success"> <c:forEach var="fileName" items="${fileNames}"> File <strong>${fileName}</strong> uploaded successfully<br/> </c:forEach> <br/> <a href="<c:url value='/welcome' />">Home</a> </div> </body> </html>
welcome.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Spring 4 MVC File Upload Example</title> <link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet"></link> <link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link> </head> <body> <div class="form-container"> <h1>Welcome to FileUploader Example</h1> Click on below links to see FileUpload in action.<br/><br/> <a href="<c:url value='/singleUpload' />">Single File Upload</a> OR <a href="<c:url value='multiUpload' />">Multi File Upload</a> </div> </body> </html>
Create Initialization class
package com.websystique.springmvc.configuration; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { HelloWorldConfiguration.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
Build, Deploy & Run Application
Now build the war (either by eclipse as was mentioned in previous tutorials) or via maven command line( mvn clean install). Deploy the war to a Servlet 3.0 container . Since here i am using Tomcat, i will simply put this war file into tomcat webapps folder and click on start.bat inside tomcat/bin directory.
Open browser and browse at http://localhost:8080/Spring4MVCFileUploadCommonsExample/
Now click on Single File Upload link.
click on Upload, without selecting a file. It should show validation failure message.
Click on Choose File.
File picker should be shown. Select a file.
Clink on Upload. File uploaded.
You can check Upload folder [C:/mytemp] for uploaded file.
Now Go back, and clink on multi upload link this time.
Click on upload without any file selection, should receive validation error.
Select files.
Clink on Upload. All selected files should be uploaded.
Finally check the storage folder [C:/mytemp].
That’s it. Next post shows the same example using Spring 3.0 specific API’s.
Download Source Code
References
If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help improve further our learning process.