Monday, January 25, 2021

Spring MVC File Upload (Multipart Request) Example

In this post we’ll see a Spring MVC file upload example for single and multiple files.

Following is the list of tools used for the Spring MVC file upload example.

  1. Spring 5.0.8 Release (Spring core, spring web, spring webmvc).
  2. Java 10
  3. commons-fileupload 1.3.3 (If using Apache Commons file upload)
  4. Tomcat server V 9.0.10
  5. Eclipse Photon 4.8.0 for Java EE development

Multipart support in Spring

Spring framework provides an interface MultipartResolver residing in org.springframework.web.multipart package for parsing multipart requests including file uploads.

Spring framework provides support for two implementations of MultipartResolver-

  • Implementation based on Apache Commons FileUpload
  • Implementation based on Servlet 3.0 support for multipart request parsing.

In this post we’ll see Spring file upload example using both of these implementations and with both Spring XML configuration and Java configuration.

Project structure

Spring file upload (multipart request) using Servlet 3.0 support

In my opinion using Servlet 3.0 support for file upload is the better option as you don’t need any additional dependencies to use it, existing servlet container (if it supports servlet 3.0 or higher) will suffice.

Required XML Configuration

To use Servlet 3.0 multipart support you need to add a bean of type StandardServletMultipartResolver in your DispatcherServlet configuration.

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"></bean>

StandardServletMultipartResolver bean has no properties to set, if you want to set some constraints on your file upload like maximum file upload size or temporary location then you need to add a "<multipart-config>" section in web.xml

<servlet>
  <servlet-name>mvcexample</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
  <multipart-config>
    <!-- 2 MB max file upload size -->
    <max-file-size>2097152</max-file-size>
  </multipart-config>
</servlet>

Required Java Configuration

If you prefer Spring Java config rather than XML configuration then you need to declare StandardServletMultipartResolver as a bean and need to set a MultipartConfigElement on the Servlet registration for setting configurations like maximum size or storage location.

For Spring MVC with Java config generally AbstractAnnotationConfigDispatcherServletInitializer is used to register DispatcherServlet and it is done automatically. In that case customizeRegistration() method is used to set a MultipartConfigElement on the Servlet registration.

Here is the full class-

import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpringMVCConfigInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  @Override
  protected Class<?>[] getRootConfigClasses() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  protected Class<?>[] getServletConfigClasses() {
    return new Class<?>[] {WebConfig.class};
  }

  @Override
  protected String[] getServletMappings() {
    return new String[] {"/"};
  }

  @Override
  protected void customizeRegistration(ServletRegistration.Dynamic registration) {
    registration.setMultipartConfig(new MultipartConfigElement("", 2097152, 4193304, 2097152));    
  }
}
Here note the method customizeRegistration which uses instance of MultipartConfigElement, description of which is as follows.
public MultipartConfigElement(String location,
                              long maxFileSize,
                              long maxRequestSize,
                              int fileSizeThreshold)
  • location- the directory location where files will be stored.
  • maxFileSize- the maximum size allowed for uploaded files.
  • maxRequestSize- the maximum size allowed formultipart/form-data requests.
  • fileSizeThreshold- the size threshold after which files will be written to disk.

Declaring StandardServletMultipartResolver as a bean – Java config

@Configuration
@EnableWebMvc
@ComponentScan(basePackages="org.netjs.controller")
public class WebConfig implements WebMvcConfigurer {
 
 @Bean
 public ViewResolver viewResolver() {
  InternalResourceViewResolver resolver = new InternalResourceViewResolver();
  resolver.setPrefix("/WEB-INF/jsp/");
  resolver.setSuffix(".jsp");
  return resolver;
 }
 
 public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
  configurer.enable();
 }
 
 @Bean
 public MultipartResolver multipartResolver() {
  return new StandardServletMultipartResolver();
 }
}

Spring file upload (multipart request) using Commons FileUpload

Another option for parsing multipart request in Spring framework is using Commons FileUpload.

Maven dependency

To use Commons FileUpload you need to have commons-fileupload as a dependency on your classpath. If you are using Maven that can be added in pom.xml as follows-
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
That adds the following jars-
commons-fileupload-1.3.3.jar
commons-io-2.2.jar

Required Spring XML Configuration

To use Apache Commons FileUpload for multipart support you need to configure a bean of type CommonsMultipartResolver with the name multipartResolver in your DispatcherServlet configuration.

<bean id="multipartResolver"   class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="2097152" />
</bean>

CommonsMultipartResolver provides "maxUploadSize", "maxInMemorySize" and "defaultEncoding" settings as bean properties itself so need to add properties in web.xml as in the case with StandardServletMultipartResolver.

Required Java Configuration

If you prefer Spring Java config then you can configure CommonsMultipartResolver as bean in the following way.

@Bean
public MultipartResolver multipartResolver() throws IOException {
 CommonsMultipartResolver cmr = new CommonsMultipartResolver();
 cmr.setMaxUploadSize(2097152);
 return cmr;
}

Views

JSP that is used for uploading a single file.

uploadFile.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
  <form action="uploadFile" method="post" enctype="multipart/form-data">
    <table>
      <tr>
        <td>
          <label>Select a file to upload:</label>
          <input type="file" name="file">
        </td>
      </tr>
      <tr>
        <td><input type="submit" value="Upload File"></td>
      </tr>
    </table>
  </form>
</body>
</html>

In the JSP, enctype="multipart/form-data" attribute is used with the form tag to specify that it is a multipart request.

JSP that is used for uploading multiple files.

uploadMultipleFiles.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring File Upload</title>
</head>
<body>
  <form action="uploadMultiFile" method="POST" enctype="multipart/form-data">
    <table>
      <tr>
        <td>
          <label>Select a file to upload:</label>
          <input type="file" name="files">
        </td>
      </tr>
      <tr>
        <td>
          <label>Select a file to upload:</label>
          <input type="file" name="files">
        </td>
      </tr>
      <tr>
        <td>
          <label>Select a file to upload:</label>
          <input type="file" name="files">
        </td>
      </tr>
      <tr>
        <td><input type="submit" value="Upload"></td>
      </tr>
    </table>
  </form>
</body>
</html>

Here note that the same name “files” is used in all the input fields. That is required so that request is sent as an array of files.

Another JSP shows the upload status by showing a message set in the controller for success or failure of the upload. Also shows some metadata about the uploaded file like name, size and content type.

uploadStatus.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<table>
  <tr>
    <td>Upload status: ${message}</td>
  </tr>
  <tr>
    <td>File Name: ${file.getOriginalFilename()}</td>
  </tr>
  <tr>
    <td>File Size: ${file.getSize()}</td>
  </tr>
  <tr>
    <td>File Type: ${file.getContentType()}</td>
  </tr>
</table>
</body>
</html> 

Controller class

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
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;

@Controller
public class FileUploadController {
  @RequestMapping(value = "/uploadMulti", method = RequestMethod.GET)
  public String startMultiUpload(Model model) {    
    return "uploadMultipleFiles";
  }

  @RequestMapping(value = "/upload", method = RequestMethod.GET)
  public String startUpload(Model model) {    
    return "uploadFile";
  }
    
  // Handler Method for file upload
  @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
  public String uploadFile(@RequestParam("file") MultipartFile file, Model model) {
    String msg= "";
    if(!file.isEmpty()) {
      BufferedOutputStream bos =null;
      try {
        byte[] fileBytes = file.getBytes();
        // location to save the file
        String fileName = "G:\\Test\\"+file.getOriginalFilename();
        bos = new BufferedOutputStream(new FileOutputStream(new File(fileName)));
        bos.write(fileBytes);
        msg = "Upload successful for " + file.getName();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }finally {
        if(bos != null) {
          try {
            bos.close();
          } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
      }
    }else {
      msg = "Upload failed for " + file.getName() + " as file is empty";
    }
    model.addAttribute("message", msg);
    model.addAttribute("file", file);
    return "uploadStatus";
  }
    
  // Handler Method for multiple file uploads
  @PostMapping(value = "/uploadMultiFile")
  @ResponseBody
  public String uploadMultipleFiles(@RequestParam("files") MultipartFile[] files, Model model) {
    String msg= "";
    int emptyCount = 0;
    for(MultipartFile file : files) {
      if(!file.isEmpty()) {
        BufferedOutputStream bos =null;
        try {
          byte[] fileBytes = file.getBytes();
          // location to save the file
          String fileName = "G:\\Test\\"+file.getOriginalFilename();
          bos = new BufferedOutputStream(new FileOutputStream(new File(fileName)));
          bos.write(fileBytes);
          msg = msg + "Upload successful for " + file.getOriginalFilename() + "<br />";
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }finally {
          if(bos != null) {
            try {
                bos.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
          }
        }
      }else {
        emptyCount++;          
      }
    }
    // Equal means no file is selected for upload
    if(files.length == emptyCount) {
      msg = "Upload failed as no file is selected";
    }
    return msg;
  }
}

In the controller class, uploadFile() method is used for handling single file upload request which has a parameter of type MultipartFile. In the logic for saving the uploaded file at a location, file path is hardcoded, you may change it to get the path from a property file or with respect to server path.

uploadMultipleFiles() method is used for handling multiple file uploads in the Spring Controller class. In the method note that MultipartFile[] parameter is an array now for holding multiple files. Method uses the new Annotation @PostMapping (from Spring 4.3) which is the shortcut for @RequestMapping(method = RequestMethod.POST).

Also uses the annotation @ResponseBody that indicates a method return value should be bound to the web response body. That way string can be returned as a response not as a logical view name to be resolved to JSP.

MultipartFile has a transferTo() method that can also be used for storing the uploaded file at the given location.

 // Handler Method for file upload
 @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
 public String uploadFile(@RequestParam("file") MultipartFile file, Model model) {
  String msg= "";
  if(!file.isEmpty()) {
   
   try {
    String fileName = "G:\\Test\\"+file.getOriginalFilename();
    // for storing uploaded file
    file.transferTo(new File(fileName));
    msg = "Upload successful for " + file.getName();
   } catch (IllegalStateException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }else {
   msg = "Upload failed for " + file.getName() + " as file is empty";
  }
  model.addAttribute("message", msg);
  model.addAttribute("file", file);
  return "uploadStatus";
 }

Screens for Spring MVC file upload exmaple

Upload page with one PDF file selected for uploading.

Spring MVC file upload

Showing the status of the upload.

Spring MVC file upload status

If upload is not successful.

Spring MVC file upload error

Upload page for multiple uploads with two files selected for uploading.

Spring MVC multiple files upload

Showing the status of the upload.

Spring MVC multiple files upload

That's all for this topic Spring MVC File Upload (Multipart Request) Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring MVC Form Example With Bean Validation
  2. Spring MVC Exception Handling Example Using @ExceptionHandler And @ControllerAdvice
  3. Difference Between @Controller And @RestController Annotations in Spring
  4. Spring Batch Processing Using JDBCTemplate batchUpdate() Method
  5. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example

You may also like-

  1. Using c-namespace in Spring
  2. Injecting Inner Bean in Spring
  3. Excluding Bean From Autowiring in Spring
  4. Using Conditional Annotation in Spring Framework
  5. Garbage Collection in Java
  6. Serialization Proxy Pattern in Java
  7. Interface Default Methods in Java 8
  8. Arrange Non-Negative Integers to Form Largest Number - Java Program

No comments:

Post a Comment