Spring MVC file upload with Validation
Spring MVC file upload with Validation
In Spring MVC application, we have already understood about single and multiple files upload in File Upload article.
In this article, we will just extend it by providing validation to the uploading file.
Validation could be to check whether file is empty or file has specified MIME type etc.
Lets develop an application
Project structure
Step 1
Create pom.xml with below dependencies
- <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>Spring</groupId>
- <artifactId>SpringFileUploadValidation</artifactId>
- <packaging>war</packaging>
- <version>0.0.1-SNAPSHOT</version>
- <name>FileUpload Maven Webapp</name>
- <url>http://maven.apache.org</url>
- <properties>
- <org.springframework.version>4.2.0.RELEASE</org.springframework.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>${org.springframework.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${org.springframework.version}</version>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.servlet.jsp.jstl</groupId>
- <artifactId>javax.servlet.jsp.jstl-api</artifactId>
- <version>1.2.1</version>
- </dependency>
- <!-- Apache Commons FileUpload -->
- <dependency>
- <groupId>commons-fileupload</groupId>
- <artifactId>commons-fileupload</artifactId>
- <version>1.3.1</version>
- </dependency>
- <!-- Apache Commons IO -->
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.4</version>
- </dependency>
- <dependency>
- <groupId>taglibs</groupId>
- <artifactId>standard</artifactId>
- <version>1.1.2</version>
- </dependency>
- </dependencies>
- <build>
- <finalName>SpringFileUploadValidation</finalName>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>2.5.1</version>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </project>
<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>Spring</groupId> <artifactId>SpringFileUploadValidation</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>FileUpload Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <org.springframework.version>4.2.0.RELEASE</org.springframework.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>javax.servlet.jsp.jstl-api</artifactId> <version>1.2.1</version> </dependency> <!-- Apache Commons FileUpload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- Apache Commons IO --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> </dependencies> <build> <finalName>SpringFileUploadValidation</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
We have added apache file upload and file io dependencies
Step 2
Create web.xml file with Dispatcher servlet
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
- version="3.1">
- <display-name>FileUpload</display-name>
- <!-- Spring MVC dispatcher servlet -->
- <servlet>
- <servlet-name>mvc-dispatcher</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/spring-mvc.xml,
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>mvc-dispatcher</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- </web-app>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>FileUpload</display-name> <!-- Spring MVC dispatcher servlet --> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring-mvc.xml, </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
We have also provided the spring configuration file name to create and load the spring beans while starting the server.
Step 3
Create the spring configuration file
Now add the multipartResolver bean in the configuration file so that spring can handle multipart requests like file upload.
- <?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:p="http://www.springframework.org/schema/p"
- 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-3.2.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.2.xsd
- http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
- <context:component-scan base-package="com.kb" />
- <mvc:annotation-driven />
- <bean id="viewResolver"
- class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/pages/" />
- <property name="suffix" value=".jsp" />
- </bean>
- <bean id="multipartResolver"
- class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
- </bean>
- <bean id="messageSource"
- class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
- <property name="basename" value="/WEB-INF/messages" />
- </bean>
- </beans>
<?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:p="http://www.springframework.org/schema/p" 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-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"> <context:component-scan base-package="com.kb" /> <mvc:annotation-driven /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/" /> <property name="suffix" value=".jsp" /> </bean> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> </bean> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="/WEB-INF/messages" /> </bean> </beans>
we have added view resolver to resolve the view name and message source bean to load the messages from messages.propertes file.
Step 4
Create the view page
uploadFile.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="spring" uri="http://www.springframework.org/tags"%>
- <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Hello</title>
- </head>
- <body>
- <form:form method="POST" action="uploadFile" enctype="multipart/form-data" modelAttribute="fileUploadModel">
- File to Upload: <input type="file" name="file"></br> </br>
- Name: <input type="text" name="name"><br /> </br>
- <input type="submit" value="Upload"></br>
- <form:errors path="file" style="color:red;"/>
- </form:form>
- </body>
- </html>
<%@ 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="spring" uri="http://www.springframework.org/tags"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Hello</title> </head> <body> <form:form method="POST" action="uploadFile" enctype="multipart/form-data" modelAttribute="fileUploadModel"> File to Upload: <input type="file" name="file"></br> </br> Name: <input type="text" name="name"><br /> </br> <input type="submit" value="Upload"></br> <form:errors path="file" style="color:red;"/> </form:form> </body> </html>
fileUploadSuccess.jsp
- <html>
- <body>
- <h2>Spring MVC file upload Success</h2>
- FileName : <strong> ${fileName} </strong> - Uploaded Successful.
- </body>
- </html>
<html> <body> <h2>Spring MVC file upload Success</h2> FileName : <strong> ${fileName} </strong> - Uploaded Successful. </body> </html>
fileUploadFailure.jsp
- <html>
- <body>
- <h2>Spring MVC file upload failure</h2>
- FileName : <strong> ${fileName} </strong> - Upload error due to some technical issues
- Please try again later.
- </body>
- </html>
<html> <body> <h2>Spring MVC file upload failure</h2> FileName : <strong> ${fileName} </strong> - Upload error due to some technical issues Please try again later. </body> </html>
Step 5
Create the controller
- package com.kb.controllers;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileOutputStream;
- import javax.servlet.ServletContext;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.validation.BindingResult;
- import org.springframework.web.bind.annotation.ModelAttribute;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.context.ServletContextAware;
- import org.springframework.web.multipart.MultipartFile;
- import org.springframework.web.servlet.ModelAndView;
- import com.kb.model.FileUploadModel;
- import com.kb.validator.CustomFileValidator;
- @Controller
- public class FileUploadController implements ServletContextAware {
- private ServletContext servletContext;
- @Autowired
- CustomFileValidator customFileValidator;
- @RequestMapping(value = "/uploadFile", method = RequestMethod.GET)
- public String uploadFileFormDisplay(Model model) {
- model.addAttribute("fileUploadModel", new FileUploadModel());
- return "uploadFile";
- }
- // Handle the single file upload
- @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
- public String uploadFileHandler(Model model,@ModelAttribute FileUploadModel fileUploadModel, BindingResult bindingResult) {
- // file handling to upload it in the server path
- MultipartFile file = fileUploadModel.getFile();
- customFileValidator.validate(fileUploadModel, bindingResult);
- if (bindingResult.hasErrors()) {
- return "uploadFile";
- }
- String fileName = file.getOriginalFilename();
- model.addAttribute("fileName", fileName);
- try {
- byte[] bytes = file.getBytes();
- BufferedOutputStream stream = new BufferedOutputStream(
- new FileOutputStream(new File(servletContext.getRealPath("/") + "/" + fileName)));
- stream.write(bytes);
- stream.close();
- return "fileUploadSuccess";
- } catch (Exception e) {
- return "fileUploadFailure";
- }
- }
- public void setServletContext(ServletContext servletContext) {
- this.servletContext = servletContext;
- }
- }
package com.kb.controllers; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import javax.servlet.ServletContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.ServletContextAware; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import com.kb.model.FileUploadModel; import com.kb.validator.CustomFileValidator; @Controller public class FileUploadController implements ServletContextAware { private ServletContext servletContext; @Autowired CustomFileValidator customFileValidator; @RequestMapping(value = "/uploadFile", method = RequestMethod.GET) public String uploadFileFormDisplay(Model model) { model.addAttribute("fileUploadModel", new FileUploadModel()); return "uploadFile"; } // Handle the single file upload @RequestMapping(value = "/uploadFile", method = RequestMethod.POST) public String uploadFileHandler(Model model,@ModelAttribute FileUploadModel fileUploadModel, BindingResult bindingResult) { // file handling to upload it in the server path MultipartFile file = fileUploadModel.getFile(); customFileValidator.validate(fileUploadModel, bindingResult); if (bindingResult.hasErrors()) { return "uploadFile"; } String fileName = file.getOriginalFilename(); model.addAttribute("fileName", fileName); try { byte[] bytes = file.getBytes(); BufferedOutputStream stream = new BufferedOutputStream( new FileOutputStream(new File(servletContext.getRealPath("/") + "/" + fileName))); stream.write(bytes); stream.close(); return "fileUploadSuccess"; } catch (Exception e) { return "fileUploadFailure"; } } public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } }
uploadFileFormDisplay method displays the file upload view page.
uploadFileHandler method handles the file upload submitted request.
This will call the custom validator to validate the file and return the appropriate view page.
Step 6
Create the custom validator class
- package com.kb.validator;
- import org.springframework.stereotype.Component;
- import org.springframework.validation.Errors;
- import org.springframework.validation.Validator;
- import org.springframework.web.multipart.MultipartFile;
- import com.kb.model.FileUploadModel;
- @Component
- public class CustomFileValidator implements Validator{
- public static final String PNG_MIME_TYPE="image/png";
- public static final long TEN_MB_IN_BYTES = 10485760;
- @Override
- public boolean supports(Class<?> clazz) {
- return FileUploadModel.class.isAssignableFrom(clazz);
- }
- @Override
- public void validate(Object target, Errors errors) {
- FileUploadModel fileUploadModel = (FileUploadModel)target;
- MultipartFile file = fileUploadModel.getFile();
- if(file.isEmpty()){
- errors.rejectValue("file", "upload.file.required");
- }
- else if(!PNG_MIME_TYPE.equalsIgnoreCase(file.getContentType())){
- errors.rejectValue("file", "upload.invalid.file.type");
- }
- else if(file.getSize() > TEN_MB_IN_BYTES){
- errors.rejectValue("file", "upload.exceeded.file.size");
- }
- }
- }
package com.kb.validator; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springframework.web.multipart.MultipartFile; import com.kb.model.FileUploadModel; @Component public class CustomFileValidator implements Validator{ public static final String PNG_MIME_TYPE="image/png"; public static final long TEN_MB_IN_BYTES = 10485760; @Override public boolean supports(Class<?> clazz) { return FileUploadModel.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { FileUploadModel fileUploadModel = (FileUploadModel)target; MultipartFile file = fileUploadModel.getFile(); if(file.isEmpty()){ errors.rejectValue("file", "upload.file.required"); } else if(!PNG_MIME_TYPE.equalsIgnoreCase(file.getContentType())){ errors.rejectValue("file", "upload.invalid.file.type"); } else if(file.getSize() > TEN_MB_IN_BYTES){ errors.rejectValue("file", "upload.exceeded.file.size"); } } }
We have written the various validation conditions in the validator class.
To understand how custom validator works, please check Spring Custom Validtion article
Step 7
Create the messages.properties file under WEB-INF directory
- upload.file.required=File can not be empty
- upload.invalid.file.type = Please upload valid .png file only
- upload.exceeded.file.size = Please upload a file with size less than 10 MB
upload.file.required=File can not be empty upload.invalid.file.type = Please upload valid .png file only upload.exceeded.file.size = Please upload a file with size less than 10 MB
These messages will be displayed in the upload file form if any validation fails.
Step 8
Deploy the application
Step 9
Lets see the output
Access the below url
http://localhost:8080/SpringFileUploadValidation/uploadFile
Now click on Submit without selecting a file
we can see the validation message in the same page.
Now Choose any file which is “not png” type and try to upload it
Give the name as you want in the Name box and Click on Upload
Now try to upload valid png file
Click on upload