// Tutorial //

Spring MVC File Upload Example Tutorial - Single and Multiple Files

Published on August 3, 2022
Default avatar
By Pankaj
Developer and author at DigitalOcean.
Spring MVC File Upload Example Tutorial - Single and Multiple Files

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

File Uploading is a very common task in any web application. We have earlier seen how to upload files in Servlet and Struts2 File Uploading. Today we will learn about Spring File upload, specifically Spring MVC File Upload for single and multiple files.

Spring MVC File Upload

Spring MVC framework provides support for uploading files by integrating Apache Commons FileUpload API. The process to upload files is very easy and requires simple configurations. We will create a simple Spring MVC project in STS that will look like below image. Spring File Uplaod Example Project, MultipartFile, MultipartResolver Most of the part is the boiler-plate code generated by STS tool, we will focus on the changes that are required to utilize Spring file upload integration.

Maven Dependencies for Apache Commons FileUpload

First of all, we need to add Apache Commons FileUpload dependencies in our pom.xml file, so that required jar files are part of the web application. Below is the dependency snippet from my pom.xml file.

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

Spring File Upload Form Views

We will create two JSP pages to allow single and multiple file uploads in spring web application. upload.jsp view code:

<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Upload File Request Page</title>
</head>
<body>
	<form method="POST" action="uploadFile" enctype="multipart/form-data">
		File to upload: <input type="file" name="file"><br /> 
		Name: <input type="text" name="name"><br /> <br /> 
		<input type="submit" value="Upload"> Press here to upload the file!
	</form>	
</body>
</html>

uploadMultiple.jsp view code:

<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Upload Multiple File Request Page</title>
</head>
<body>
	<form method="POST" action="uploadMultipleFile" enctype="multipart/form-data">
		File1 to upload: <input type="file" name="file"><br /> 
		Name1: <input type="text" name="name"><br /> <br /> 
		File2 to upload: <input type="file" name="file"><br /> 
		Name2: <input type="text" name="name"><br /> <br />
		<input type="submit" value="Upload"> Press here to upload the file!
	</form>
</body>
</html>

Notice that these files are simple HTML files, I am not using any JSP or Spring tags to avoid complexity. The important point to note is that form enctype should be multipart/form-data, so that Spring web application knows that the request contains file data that needs to be processed. Also note that for multiple files, the form field “file” and “name” are the same in the input fields, so that the data will be sent in the form of an array. We will take the input array and parse the file data and store it in the given file name.

Spring MVC Multipart Configuration

To utilize Apache Commons FileUpload for handling multipart requests, all we need to do is configure multipartResolver bean with class as org.springframework.web.multipart.commons.CommonsMultipartResolver. Our final Spring configuration file looks like below. servlet-context.xml code:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
	xmlns:context="https://www.springframework.org/schema/context"
	xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing 
		infrastructure -->

	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving 
		up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/**" location="/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources 
		in the /WEB-INF/views directory -->
	<beans:bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>

	<beans:bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

		 <!-- setting maximum upload size -->
		<beans:property name="maxUploadSize" value="100000" />

	</beans:bean>

	<context:component-scan base-package="com.journaldev.spring.controller" />

</beans:beans>

Notice that I am setting maximum upload size limit by providing the maxUploadSize property value for multipartResolver bean. If you will look into the source code of DispatcherServlet class, you will see that a MultipartResolver variable with name multipartResolver is defined and initialized in below method.

private void initMultipartResolver(ApplicationContext context)
  {
    try
    {
      this.multipartResolver = ((MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class));
      if (this.logger.isDebugEnabled()) {
        this.logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
      }
    }
    catch (NoSuchBeanDefinitionException ex)
    {
      this.multipartResolver = null;
      if (this.logger.isDebugEnabled())
        this.logger.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
    }
  }

With this configuration, any request with enctype as multipart/form-data will be handled by multipartResolver before passing on to the Controller class.

Spring File Upload Controller Class

Controller class code is very simple, we need to define handler methods for the uploadFile and uploadMultipleFile URIs. FileUploadController.java code:

package com.journaldev.spring.controller;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
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.multipart.MultipartFile;

/**
 * Handles requests for the application file upload requests
 */
@Controller
public class FileUploadController {

	private static final Logger logger = LoggerFactory
			.getLogger(FileUploadController.class);

	/**
	 * Upload single file using Spring Controller
	 */
	@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
	public @ResponseBody
	String uploadFileHandler(@RequestParam("name") String name,
			@RequestParam("file") MultipartFile file) {

		if (!file.isEmpty()) {
			try {
				byte[] bytes = file.getBytes();

				// Creating the directory to store file
				String rootPath = System.getProperty("catalina.home");
				File dir = new File(rootPath + File.separator + "tmpFiles");
				if (!dir.exists())
					dir.mkdirs();

				// Create the file on server
				File serverFile = new File(dir.getAbsolutePath()
						+ File.separator + name);
				BufferedOutputStream stream = new BufferedOutputStream(
						new FileOutputStream(serverFile));
				stream.write(bytes);
				stream.close();

				logger.info("Server File Location="
						+ serverFile.getAbsolutePath());

				return "You successfully uploaded file=" + name;
			} catch (Exception e) {
				return "You failed to upload " + name + " => " + e.getMessage();
			}
		} else {
			return "You failed to upload " + name
					+ " because the file was empty.";
		}
	}

	/**
	 * Upload multiple file using Spring Controller
	 */
	@RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST)
	public @ResponseBody
	String uploadMultipleFileHandler(@RequestParam("name") String[] names,
			@RequestParam("file") MultipartFile[] files) {

		if (files.length != names.length)
			return "Mandatory information missing";

		String message = "";
		for (int i = 0; i < files.length; i++) {
			MultipartFile file = files[i];
			String name = names[i];
			try {
				byte[] bytes = file.getBytes();

				// Creating the directory to store file
				String rootPath = System.getProperty("catalina.home");
				File dir = new File(rootPath + File.separator + "tmpFiles");
				if (!dir.exists())
					dir.mkdirs();

				// Create the file on server
				File serverFile = new File(dir.getAbsolutePath()
						+ File.separator + name);
				BufferedOutputStream stream = new BufferedOutputStream(
						new FileOutputStream(serverFile));
				stream.write(bytes);
				stream.close();

				logger.info("Server File Location="
						+ serverFile.getAbsolutePath());

				message = message + "You successfully uploaded file=" + name
						+ "<br />";
			} catch (Exception e) {
				return "You failed to upload " + name + " => " + e.getMessage();
			}
		}
		return message;
	}
}

Notice the use of Spring annotations that make our life easier and code looks more readable. uploadFileHandler method is used to handle single file upload scenario whereas uploadMultipleFileHandler method is used to handle multiple files upload scenario. Actually we could have a single method to handle both the scenarios. Now export the application as WAR file and deploy it into Tomcat servlet container. When we run our application, below images shows us the request and responses.

Spring MVC File Upload Example

Spring MVC Single File Upload Form Spring MVC Single File Upload Response Spring MVC Multiple File Upload Example Spring Multiple File Upload Response You can check the server logs to know the location where the files have been stored. Download the project from the above link and play around with it to learn more.

Download Spring File Upload Project

If you’ve enjoyed this tutorial and our broader community, consider checking out our DigitalOcean products which can also help you achieve your development goals.

Learn more here


About the authors
Default avatar
Pankaj

author

Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?

public List uploadMultipleFiles(@RequestParam(“files”) MultipartFile[] files) { I am trying this singnature but facing the below error, Please help “message”: “Current request is not a multipart request”, “trace”: “org.springframework.web.multipart.MultipartException: Current request is not a multipart request\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:158)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:660)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:741)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.base/java.lang.Thread.run(Thread.java:830)\n”

- Abhishek

    great help full sir

    - agastyakumar

      HI i am getting 404 not found. My controller mapping should be correct because i am able to reach other methods in the same class which are not handling multipart. Servlet.xml: Controller: exactly same Jsp: same code copied to my jsp Thanks in advance Manu

      - Manu Gupta

        very helpful tutorial. can you please provide me annotation based configuration as i don want to use servlet-contex.xml and root-contex.xml

        - vishwa

          Getting status 400-Required String Parameter ‘name’ is not present

          - Himanshu Sharma

            hi could you explain how to run it with apache tompcat 8.5 thanks

            - Cristian

              I am getting the error “Application download did not succeed. Check network connection.”. Upto Server File Creation Program works fine.But the folder is not created at specified location. Plz reply.

              - Sujata

                Did any one faces MVC Portlet Mode mappings conflict between method and type level: [uploadFile] versus [VIEW]

                - Jam

                  i have a program than submit things to db . i want to add submit file to my code. i want help code in controller @RequestMapping(value = “/rest/add-new-record/{tableName}”, method = RequestMethod.POST) public String addNewRecord(@PathVariable String tableName, @RequestParam Map allRequestParams, HttpServletRequest request) throws SQLException { tableContentService.addNewRow(allRequestParams, tableName); TableMetaData metaData=getTableMetaData(tableName); metaData.getColumnMetaData(); ColumnMetaData columnMetaData=new ColumnMetaData(); return “content-manager”; } code in service public void addNewRow(Map recordData, String tableName) throws SQLException { tableContentDAO.addNewRecord(recordData,tableName, null); } //class java public void addNewRecord(Map recordData, String tableName, String id) throws SQLException { OracleConnection connection = (OracleConnection) getConnection(); Statement statement; Set columnNames = recordData.keySet(); List listValues = new ArrayList(); ResultSet resultSet = null; String pk_column = null; DatabaseMetaData databaseMetaData = connection.getMetaData(); resultSet = databaseMetaData.getPrimaryKeys(null, connection.getUserName(), tableName); while (resultSet.next()) { pk_column = resultSet.getString(“COLUMN_NAME”); } // System.out.println(“pk_column==================”+ pk_column); for (Map.Entry stringStringEntry : recordData.entrySet()) { String help = null; if (!stringStringEntry.getKey().equals(pk_column)) { if (isValidDate((String) stringStringEntry.getValue())) { help = " TO_DATE(’ " + stringStringEntry.getValue() + " ‘, ‘YYYY/MM/DD’)“; listValues.add(help); }//if is file else { listValues.add((String) stringStringEntry.getValue()); } } } StringJoiner columnNameJoiner = new StringJoiner(”,“); columnNameJoiner.add(pk_column); // System.out.println(“columnNameJoiner=================”+ columnNameJoiner); for (String columnName : columnNames) { if (columnName != null && !columnName.equals(pk_column) && !columnName.equals(“username”)) { columnNameJoiner.add(columnName); } } // System.out.println(“columnNameJoiner=================”+ columnNameJoiner); StringJoiner recordDataJoiner = new StringJoiner(”,“); for (String value : listValues) { if (value.contains(“TO_DATE”)) { recordDataJoiner.add(value); } else { recordDataJoiner.add(”’" + value + “'”); } } //******************************************************************************************************* String query; // columnNameJoiner.toString() ID,ID,NAME /*if (id == null) { query = String.format(“Insert into %s (%s) values” + " ((SELECT COALESCE(MAX(%s)+1,1) FROM %s) ,%s)“, tableName, columnNameJoiner.toString(), pk_column, tableName, recordDataJoiner.toString()); } else { query = String.format(“Insert into %s (%s) values (%s ,%s)”, tableName, columnNameJoiner.toString(), id, recordDataJoiner.toString()); } }*/ query = String.format(“Insert into %s (%s) values” + " ((SELECT COALESCE(MAX(%s)+1,1) FROM %s) ,%s)”, tableName, columnNameJoiner.toString(), pk_column, tableName, recordDataJoiner.toString()); System.out.println(query); statement = connection.createStatement(); statement.executeQuery(query); JdbcUtils.closeConnection(connection); } code in js function createFile(field) { var required = field.required ? “required” : “”; var html=“”; //todo AliMohamadi: readable writable difference // var disabled = field. html +=“”; html +=“”; html += field.comment; html += “”; return html; }

                  - kalantary

                    Hi Pankaj, Could you please also explain how we can return file content from spring controller.

                    - Sahas