Close

Spring MVC - File upload by using StandardServletMultipartResolver

[Last Updated: Jun 9, 2026]

This example shows how to use StandardServletMultipartResolver to upload a file. This resolver is based on the Servlet 3.0 javax.servlet.http.Part API.

Also check out this tutorial to understand how MultipartResolver works.

Other than registering StandardServletMultipartResolver as a bean, we also need to set a javax.servlet.MultipartConfigElement on the Servlet registration which does configuration equivalent to using javax.servlet.annotation.MultipartConfig annotation. Check out this related Servlet example.

Example

We are going to reuse our last example, we just need to modify our Java Config and WebApplicationInitializer implementation.

Java Config

package com.logicbig.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@EnableWebMvc
@Configuration
@ComponentScan
public class MyWebConfig implements WebMvcConfigurer {

    @Bean
    public MultipartResolver multipartResolver() {
        StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
        //resolver.setResolveLazily(true);
        return resolver;
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        registry.viewResolver(viewResolver);
    }
}
package com.logicbig.example;

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

public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        // Return root configuration classes (often for service/repository layer)
        // If none, return null
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        // Return Spring MVC configuration class (the equivalent of MyWebConfig)
        return new Class<?>[]{MyWebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        // Map DispatcherServlet to root context
        return new String[]{"/"};
    }

    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        // Set multipart configuration – this is the key difference from WebApplicationInitializer
        String tempDir = System.getProperty("java.io.tmpdir");
        MultipartConfigElement multipartConfig = new MultipartConfigElement(
                tempDir,          // location
                50_000_000L,      // maxFileSize (bytes)
                50_000_000L,      // maxRequestSize (bytes)
                0                 // fileSizeThreshold (bytes)
        );
        registration.setMultipartConfig(multipartConfig);
    }
}

The Controller

package com.logicbig.example;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@Controller
@RequestMapping("/upload")
public class FileUploadController {
    public static final String TARGET_FOLDER = "d:/filesUploaded/";

    @GetMapping
    public String handleGetRequest() {
        return "file-upload";
    }

    @PostMapping
    public String handlePostRequest(MultipartHttpServletRequest request,
                                    Model model) throws IOException {

        MultipartFile multipartFile = request.getFile("user-file");
        String name = multipartFile.getOriginalFilename();
        InputStream inputStream = multipartFile.getInputStream();

        Files.copy(inputStream,
                   Paths.get(TARGET_FOLDER + name),
                   StandardCopyOption.REPLACE_EXISTING);
        model.addAttribute("msg", "File has been uploaded. name:  " + name +
                ", content: " + new String(multipartFile.getBytes()));
        return "response";
    }
}

To try examples, run embedded Jetty (configured in pom.xml of example project below):

mvn jetty:run

Output

In above form choose the file and click 'Upload File' button

Using cURL

We can use the cURL -F (or --form) flag to send raw text content as multipart/form-data. To make your backend framework treat it as a real file upload, append a dummy filename to the string:

$ curl -s -F "user-file=my file content;filename=text.txt" http://localhost:8080/upload

<html>
<body>

<h3> Upload File Response </h3>
File has been uploaded. name: text.txt, content: my file content
</form>
</body>
</html>

Integration Test

package com.logicbig.example;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.web.context.WebApplicationContext;

import java.io.File;
import java.nio.file.Files;

import static org.assertj.core.api.Assertions.assertThat;

@SpringJUnitWebConfig(MyWebConfig.class)
public class UploadControllerTest {

    @Autowired
    private WebApplicationContext wac;
    private MockMvcTester mockMvcTester;

    @BeforeEach
    public void setup() {
        this.mockMvcTester = MockMvcTester.from(this.wac);
    }

    @Test
    public void testController() throws Exception {

        String fileName = "test.txt";
        File file = new File(FileUploadController.TARGET_FOLDER + fileName);
        file.delete();

        MockMultipartFile mockMultipartFile =
                new MockMultipartFile("user-file",
                                      "test.txt",
                                      null,
                                      "test data".getBytes());

        assertThat(this.mockMvcTester.post()
                                     .uri("/upload")
                                     .multipart()
                                     .file(mockMultipartFile))
                .hasStatusOk()
                .model()
                .containsEntry("msg",
                               "File has been uploaded."
                                       + " name:  test.txt, "
                                       + "content: test data");

        assertThat(file).exists();
        assertThat(Files.readAllBytes(file.toPath())).asString().isEqualTo("test data");
    }
}
mvn clean test -Dtest="UploadControllerTest"

Output

$ mvn clean test -Dtest="UploadControllerTest"
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for com.logicbig.example:spring-standard-servlet-multipartresolver:war:1.0-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-war-plugin is missing. @ line 43, column 21
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] ---< com.logicbig.example:spring-standard-servlet-multipartresolver >---
[INFO] Building spring-standard-servlet-multipartresolver 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ spring-standard-servlet-multipartresolver ---
[INFO] Deleting D:\example-projects\spring-mvc\file-upload\spring-standard-servlet-multipart-resolver\target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ spring-standard-servlet-multipartresolver ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\file-upload\spring-standard-servlet-multipart-resolver\src\main\resources
[INFO]
[INFO] --- compiler:3.5.1:compile (default-compile) @ spring-standard-servlet-multipartresolver ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to D:\example-projects\spring-mvc\file-upload\spring-standard-servlet-multipart-resolver\target\classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ spring-standard-servlet-multipartresolver ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\file-upload\spring-standard-servlet-multipart-resolver\src\test\resources
[INFO]
[INFO] --- compiler:3.5.1:testCompile (default-testCompile) @ spring-standard-servlet-multipartresolver ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:\example-projects\spring-mvc\file-upload\spring-standard-servlet-multipart-resolver\target\test-classes
[INFO]
[INFO] --- surefire:3.2.5:test (default-test) @ spring-standard-servlet-multipartresolver ---
[INFO] Using auto detected provider org.apache.maven.surefire.junit4.JUnit4Provider
[WARNING] file.encoding cannot be set as system property, use <argLine>-Dfile.encoding=...</argLine> instead
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.logicbig.example.UploadControllerTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.511 s -- in com.logicbig.example.UploadControllerTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.757 s
[INFO] Finished at: 2026-06-05T10:09:14+08:00
[INFO] ------------------------------------------------------------------------

Using MultipartHttpServletRequest

Instead of using MultipartFile as the handler method parameter, we can alternatively use org.springframework.web.multipart.MultipartHttpServletRequest. Complete example here

Using javax.servlet.http.Part

When using StandardServletMultipartResolver, instead of MultipartFile/MultipartHttpServletRequest as the controller's handler method argument, we can alternatively use javax.servlet.http.Part. Complete example here

Example Project

Dependencies and Technologies Used:

  • spring-webmvc 7.0.6 (Spring Web MVC)
     Version Compatibility: 3.2.9.RELEASE - 7.0.6Version List
    ×

    Version compatibilities of spring-webmvc with this example:

      javax.servlet-api:3.x
    • 3.2.9.RELEASE
    • 3.2.10.RELEASE
    • 3.2.11.RELEASE
    • 3.2.12.RELEASE
    • 3.2.13.RELEASE
    • 3.2.14.RELEASE
    • 3.2.15.RELEASE
    • 3.2.16.RELEASE
    • 3.2.17.RELEASE
    • 3.2.18.RELEASE
    • 4.0.0.RELEASE
    • 4.0.1.RELEASE
    • 4.0.2.RELEASE
    • 4.0.3.RELEASE
    • 4.0.4.RELEASE
    • 4.0.5.RELEASE
    • 4.0.6.RELEASE
    • 4.0.7.RELEASE
    • 4.0.8.RELEASE
    • 4.0.9.RELEASE
    • 4.1.0.RELEASE
    • 4.1.1.RELEASE
    • 4.1.2.RELEASE
    • 4.1.3.RELEASE
    • 4.1.4.RELEASE
    • 4.1.5.RELEASE
    • 4.1.6.RELEASE
    • 4.1.7.RELEASE
    • 4.1.8.RELEASE
    • 4.1.9.RELEASE
    • 4.2.0.RELEASE
    • 4.2.1.RELEASE
    • 4.2.2.RELEASE
    • 4.2.3.RELEASE
    • 4.2.4.RELEASE
    • 4.2.5.RELEASE
    • 4.2.6.RELEASE
    • 4.2.7.RELEASE
    • 4.2.8.RELEASE
    • 4.2.9.RELEASE
    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • 4.3.2.RELEASE
    • 4.3.3.RELEASE
    • 4.3.4.RELEASE
    • 4.3.5.RELEASE
    • 4.3.6.RELEASE
    • 4.3.7.RELEASE
    • 4.3.8.RELEASE
    • 4.3.9.RELEASE
    • 4.3.10.RELEASE
    • 4.3.11.RELEASE
    • 4.3.12.RELEASE
    • 4.3.13.RELEASE
    • 4.3.14.RELEASE
    • 4.3.15.RELEASE
    • 4.3.16.RELEASE
    • 4.3.17.RELEASE
    • 4.3.18.RELEASE
    • 4.3.19.RELEASE
    • 4.3.20.RELEASE
    • 4.3.21.RELEASE
    • 4.3.22.RELEASE
    • 4.3.23.RELEASE
    • 4.3.24.RELEASE
    • 4.3.25.RELEASE
    • 4.3.26.RELEASE
    • 4.3.27.RELEASE
    • 4.3.28.RELEASE
    • 4.3.29.RELEASE
    • 4.3.30.RELEASE
    • 5.0.0.RELEASE
    • 5.0.1.RELEASE
    • 5.0.2.RELEASE
    • 5.0.3.RELEASE
    • 5.0.4.RELEASE
    • 5.0.5.RELEASE
    • 5.0.6.RELEASE
    • 5.0.7.RELEASE
    • 5.0.8.RELEASE
    • 5.0.9.RELEASE
    • 5.0.10.RELEASE
    • 5.0.11.RELEASE
    • 5.0.12.RELEASE
    • 5.0.13.RELEASE
    • 5.0.14.RELEASE
    • 5.0.15.RELEASE
    • 5.0.16.RELEASE
    • 5.0.17.RELEASE
    • 5.0.18.RELEASE
    • 5.0.19.RELEASE
    • 5.0.20.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.2.16.RELEASE
    • 5.2.17.RELEASE
    • 5.2.18.RELEASE
    • 5.2.19.RELEASE
    • 5.2.20.RELEASE
    • 5.2.21.RELEASE
    • 5.2.22.RELEASE
    • 5.2.23.RELEASE
    • 5.2.24.RELEASE
    • 5.2.25.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • javax.servlet-api:4.x
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8
    • 5.3.9
    • 5.3.10
    • 5.3.11
    • 5.3.12
    • 5.3.13
    • 5.3.14
    • 5.3.15
    • 5.3.16
    • 5.3.17
    • 5.3.18
    • 5.3.19
    • 5.3.20
    • 5.3.21
    • 5.3.22
    • 5.3.23
    • 5.3.24
    • 5.3.25
    • 5.3.26
    • 5.3.27
    • 5.3.28
    • 5.3.29
    • 5.3.30
    • 5.3.31
    • 5.3.32
    • 5.3.33
    • 5.3.34
    • 5.3.35
    • 5.3.36
    • 5.3.37
    • 5.3.38
    • 5.3.39
    • javax.* -> jakarta.*
      jakarta.servlet-api:6.x
      Java 17 min
    • 6.0.0
    • 6.0.1
    • 6.0.2
    • 6.0.3
    • 6.0.4
    • 6.0.5
    • 6.0.6
    • 6.0.7
    • 6.0.8
    • 6.0.9
    • 6.0.10
    • 6.0.11
    • 6.0.12
    • 6.0.13
    • 6.0.14
    • 6.0.15
    • 6.0.16
    • 6.0.17
    • 6.0.18
    • 6.0.19
    • 6.0.20
    • 6.0.21
    • 6.0.22
    • 6.0.23
    • 6.1.0
    • 6.1.1
    • 6.1.2
    • 6.1.3
    • 6.1.4
    • 6.1.5
    • 6.1.6
    • 6.1.7
    • 6.1.8
    • 6.1.9
    • 6.1.10
    • 6.1.11
    • 6.1.12
    • 6.1.13
    • 6.1.14
    • 6.1.15
    • 6.1.16
    • 6.1.17
    • 6.1.18
    • 6.1.19
    • 6.1.20
    • 6.1.21
    • 6.2.0
    • 6.2.1
    • 6.2.2
    • 6.2.3
    • 6.2.4
    • 6.2.5
    • 6.2.6
    • 6.2.7
    • 6.2.8
    • 6.2.9
    • 6.2.10
    • 6.2.11
    • 6.2.12
    • 6.2.13
    • 6.2.14
    • 6.2.15
    • 6.2.16
    • 6.2.17
    • 6.2.18
    • 7.0.0
    • 7.0.1
    • 7.0.2
    • 7.0.3
    • 7.0.4
    • 7.0.5
    • 7.0.6

    Versions in green have been tested.

  • spring-test 7.0.6 (Spring TestContext Framework)
  • jakarta.servlet-api 6.1.0 (Jakarta Servlet API documentation)
  • jakarta.servlet.jsp.jstl 3.0.1 (Jakarta Standard Tag Library Implementation)
  • junit-jupiter-engine 6.0.3 (Module "junit-jupiter-engine" of JUnit)
  • hamcrest 3.0 (Core API and libraries of hamcrest matcher framework)
  • assertj-core 3.26.3 (Rich and fluent assertions for testing in Java)
  • JDK 25
  • Maven 3.9.11

Spring MVC- StandardServletMultipartResolver Example Select All Download
  • spring-standard-servlet-multipart-resolver
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • MyWebConfig.java
          • webapp
            • WEB-INF
              • views
        • test
          • java
            • com
              • logicbig
                • example

    See Also

    Join