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

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
<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

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
<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.

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
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ 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

1
2
3
4
5
6
7
<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

1
2
3
4
5
6
7
8
<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

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
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

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
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

1
2
3
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

About the Author

Karibasappa G C (KB)
Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on