This tutorial shows you about Spring MVC File Upload Validation Example. This example uses Spring validator to validate the uploaded file. When the file is empty or exceeds the maximum allowed upload size, the exception is caught and response a appropriate message.
If you don’t know about Spring MVC yet, firstly you should refer to the post Spring MVC Annotation Example
Other interesting posts you may like
Table of contents:
1. Maven Dependencies
2. Project Structure
3. Spring MVC File Upload Java/XML Configuration
4. Spring MVC File Upload
5. Spring MVC File Upload Exception Handling
6. Upload file views
7. Deploy Spring MVC File Upload Validation Example
Now, we are ready to build the Spring MVC File Upload Validation Example step by step
Maven Dependencies
We added the commons-fileupload which is used to upload a MultipartFile. We also include the javax.validation API so we can annotate our controller methods with the @Valid annotation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javabycode.spring.mvc</groupId> <artifactId>spring-mvc-file-upload</artifactId> <version>1.0.0-SNAPSHOT</version> <name>SPRING-MVC - ${project.artifactId}</name> <url>http://javabycode.com</url> <packaging>war</packaging> <properties> <encoding>UTF-8</encoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <!-- spring dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- apache file upload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- java bean validation --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <!-- servlet api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> <build> <finalName>spring-mvc-file-upload</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project> |
Project Structure
The Project structure will looks like the following structure.
Spring MVC File Upload Java/XML Configuration
The CommonsMultipartResolver saves temporary files to the temporary directory in application server. The following properties should be configured for the file upload operation: maxUploadSize, maxUploadSizePerFile, maxInMemorySize, uploadDir, defaultEncoding and resolveLazily. Although they are optionally but you need to set the property resolveLazily to true if you want to catch execption correctly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package com.javabycode.config; 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.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @EnableWebMvc @Configuration @ComponentScan({"com.javabycode"}) public class MyWebConfig extends WebMvcConfigurerAdapter { @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource; } @Bean(name="multipartResolver") public CommonsMultipartResolver multipartResolver(){ CommonsMultipartResolver resolver = new CommonsMultipartResolver(); resolver.setMaxUploadSizePerFile(10240); //10Kb resolver.setDefaultEncoding("UTF-8"); resolver.setResolveLazily(true); return resolver; } @Bean public InternalResourceViewResolver viewResolver(){ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; } } |
If you want to adapt the file upload feature into your current Spring MVC XML configuration. You can add the below configuration. It is equivalent with the above java configuration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<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" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <mvc:annotation-driven /> <context:component-scan base-package="com.javabycode" /> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="messages"/> </bean> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSizePerFile" value="10240"/> <property name="defaultEncoding" value="UTF-8"/> <property name="resolveLazily" value="true"/> </bean> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> </beans> |
For simplicity, the navigation cases will be put in a NavigationController.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.javabycode.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class NavigationController { @RequestMapping(value = "/success", method = RequestMethod.GET) public String success(){ return "success"; } @RequestMapping(value = "/error", method = RequestMethod.GET) public String error(){ return "error"; } } |
Validation Messages
These validation messages are used to display an appropriate message with an error operation to the user. These messags are stored in the property file messages.properties that is located in the src/main/resources/ folder.
1 2 |
file.empty = Please select a file. file.maxsize = {0} exceeds the maximum size of {1} Kb. |
Spring MVC File Upload
The FileModel has a MultipartFile object which will hold the uploaded file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.javabycode.model; import org.springframework.web.multipart.MultipartFile; public class FileModel { MultipartFile file; public MultipartFile getFile() { return file; } public void setFile(MultipartFile file) { this.file = file; } } |
Next, you have to define the FileUploadController that is responsible for uploading a file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package com.javabycode.controller; import com.javabycode.model.FileModel; import com.javabycode.validator.FileValidator; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.validation.Valid; import java.io.File; import java.io.IOException; import java.io.InputStream; @Controller @RequestMapping("/") public class FileUploadController { @Autowired private FileValidator fileValidator; @ModelAttribute public FileModel fileModel(){ return new FileModel(); } @InitBinder protected void initBinderFileModel(WebDataBinder binder) { binder.setValidator(fileValidator); } @RequestMapping(method = RequestMethod.GET) public String single(){ return "index"; } @RequestMapping(method = RequestMethod.POST) public String handleFormUpload(@Valid FileModel fileModel, BindingResult result, RedirectAttributes redirectMap) throws IOException { if (result.hasErrors()){ return "index"; } MultipartFile file = fileModel.getFile(); InputStream in = file.getInputStream(); File destination = new File("/tmp/" + file.getOriginalFilename()); FileUtils.copyInputStreamToFile(in, destination); redirectMap.addFlashAttribute("filename", file.getOriginalFilename()); return "redirect:success"; } } |
Let’s dig deeper
The FileUploadController will upload a file to a /tmp/ directory. We bind the FileValidator onto the controller by using the @InitBinder annotation and provide a WebDataBinder as an argument in the initBinderFileModel method.
Finally, we create the handleFormUpload method to handle the file upload. By annotating the FileModel with the @Valid annotation, the binded validators are automatically executed on form submission. The RedirectAttributes is used to forward the response to a success page and the BindingResult is used to redirect to the current page if any errors have occurred.
If the file is empty, we will provide an appropriate error message by using the validator such as below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package com.javabycode.validator; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import com.javabycode.model.FileModel; @Component public class FileValidator implements Validator { @Override public boolean supports(Class<?> clazz) { return FileModel.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { FileModel fileModel = (FileModel) target; if (fileModel.getFile() != null && fileModel.getFile().isEmpty()){ errors.rejectValue("file", "file.empty"); } } } |
Spring MVC File Upload Exception Handling
You need to add a global exception handler to catch the MultipartException because it is thrown before reaching the controller. This exception handler is registered with container by using the @ControllerAdvice annotation. The methods are annotated with the @ExceptionHandler annotation to handle specific exceptions. The implementation of methods are detailed such as the below code snippet.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
package com.javabycode.exception; import org.apache.commons.fileupload.FileUploadBase; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.FlashMap; import org.springframework.web.servlet.support.RequestContextUtils; import org.springframework.web.servlet.view.RedirectView; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @ControllerAdvice public class GlobalExceptionHandler { @Autowired private MessageSource messageSource; @ExceptionHandler(value = MultipartException.class) public RedirectView handleMultipartException(Exception ex, HttpServletRequest request){ RedirectView model = new RedirectView("error"); FlashMap flash = RequestContextUtils.getOutputFlashMap(request); if (ex instanceof MultipartException) { MultipartException mEx = (MultipartException)ex; if (ex.getCause() instanceof FileUploadBase.FileSizeLimitExceededException){ FileUploadBase.FileSizeLimitExceededException flEx = (FileUploadBase.FileSizeLimitExceededException)mEx.getCause(); float permittedSize = flEx.getPermittedSize() / 1024; String message = messageSource.getMessage( "file.maxsize", new Object[]{flEx.getFileName(), permittedSize}, LocaleContextHolder.getLocale()); flash.put("errors", message); } else { flash.put("errors", "Please contact administrator: " + ex.getMessage()); } } else { flash.put("errors", "Please contact administrator: " + ex.getMessage()); } return model; } @ExceptionHandler(value = IOException.class) public RedirectView handleIOException(Exception ex, HttpServletRequest request){ RedirectView model = new RedirectView("error"); FlashMap flash = RequestContextUtils.getOutputFlashMap(request); flash.put("errors", "Please contact administrator: " + ex.getMessage()); return model; } } |
Upload file views
We created a simple view to upload a file.
Upload view
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Spring MVC File Upload Example + Validator</title> <style> .error { color: red; } </style> </head> <body> <h1>Spring MVC File Upload Example + Validator</h1> <form:form method="post" modelAttribute="fileModel" enctype="multipart/form-data"> Upload File: <form:input type="file" path="file" id="file"/> <br/> <form:errors path="file" cssClass="error"/> <br/><br/> <input type="submit" value="Upload"> </form:form> </body> </html> |
Success View
When the file is successfully uploaded, the file name will displayed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Success</title> </head> <body> <h1>Success</h1> <c:if test="${not empty filename}"> ${filename} uploaded successfully. <br/><br/> </c:if> <c:if test="${not empty filenames}"> <c:forEach var="file" items="${filenames}"> ${file} uploaded successfully. <br/> </c:forEach> <br/><br/> </c:if> <a href="<c:url value='/'/>">Upload Page</a> </body> </html> |
Error View
The content of the error is displayed if an error occurs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Error</title> <style> .error { color: red; } </style> </head> <body> <h1>Error</h1> <span class="error">${errors}</span> <br/><br/> <a href="<c:url value='/'/>">Upload Page</a> </body> </html> |
Deploy Spring MVC File Upload Validation Example
Building project with maven then deploy file war on application server or servlet container (Tomcat 8 for example). Access the address URL http://localhost:8080/spring-mvc-file-upload/ and browse a file to upload such as the below screen shot.
Click the Upload button the success screen will display
Click the Upload Page link to return the Upload form screen and browse other file that its size exceeds 10 Kb. The error screen will display such as
That’s it on how to build Spring MVC File Upload Validation Example. The next tutorial will show you about Spring MVC Multiple File Upload Validation Example
Download complete source code of example, please click link below
Spring-MVC-File-Upload-Validation-Example.zip (383 downloads)
Source code on Github https://github.com/javabycode/spring-mvc-file-upload-validation-example