Multipart Resolver
来自org.springframework.web.multipart包下的MultipartResolver提供解析包括文件上传在内的多部分请求策略。一种实现方式是基于Commons FileUpload,另外则基于Servlet 3.0的多部分请求解析。
启用多部分处理,需要在DispatcherServletSpring配置中声明一个名为multipartResolver的MultipartResolverbean。DispatcherServlet检测到它并将其应用于传入的请求。当接收到一个content-type是multipart/form-data的POST请求时,解析程序将解析内容并将当前HttpServletRequest包装为MultipartHttpServletRequest,以提供对已解析部分的访问权限,此外将其作为请求参数公开。
Apache Commons FileUpload
使用Apache Commons FileUpload,需要配置名称为multipartResolver的CommonsMultipartResolver类型的Bean。 还需要引入commons-fileupload的依赖。
Servlet 3.0
启用Servlet 3.0多部分解析需要通过Servlet容器配置。操作如下:
- 通过Java配置, 在Servlet注册器中设置一个
MultipartConfigElement。 - 通过web.xml, 在servlet定义中添加
<multipart-config>部分。
代码实现
Spring MVC环境配置
通过MAVEN构建一个maven-archetypeweb-app项目,通过Java代码形式配置SpringMVC,具体配置方式如下。
pom.xml,引入依赖
<properties>
...
<spring.version>5.2.2.RELEASE</spring.version>
<tomcat.version>8.5.5</tomcat.version>
</properties>
<dependencies>
<!--spring -core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
Spring MVC配置
AppConfig.java
@Configuration
@ComponentScan("io.github.nirvanafire")
public class AppConfig implements WebMvcConfigurer {
...
}
MyWebApplicationInitializer.java
public class MyWebApplicationInitializer implements WebApplicationInitializer {
private int MAX_UPLOAD_SIZE = 5 * 1024 * 1024;
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("---MyApplicationInitializer onStartup---");
// 加载Spring Web应用配置
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext ();
ac.register(AppConfig.class);
ac.refresh();
// 创建并注册DispatcherServlet(前端控制器)
DispatcherServlet ds = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletContext.addServlet("dispatchServlet", ds);
registration.setLoadOnStartup(1);
registration.addMapping("*.do");
}
}
文件上传Controller实现
@RestController
public class UploadController {
@PostMapping("/upload_commons")
public String uploadCommons(@RequestPart("file") MultipartFile file) {
System.out.println("---Run Upload Commons---");
storeFile(file);
return "success";
}
private void storeFile(MultipartFile file) {
try {
String originalFilename = file.getOriginalFilename();
System.out.println("----File Name: " + originalFilename + "----");
File tmpFolder = new File("tmp");
if (!tmpFolder.exists()) {
tmpFolder.mkdir();
}
File tmp = new File("tmp/" + originalFilename);
FileOutputStream fos = new FileOutputStream(tmp);
FileCopyUtils.copy(file.getInputStream(), fos);
} catch (IOException e) {
System.out.println("Upload File Error: " + e.getMessage());
}
}
}
页面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SpringMVC-UploadFile</title>
</head>
<body>
<h1>SpringMVC-UploadFile</h1>
<hr>
<h2>Apache Commons FileUpload</h2>
<form action="/upload_commons.do" enctype="multipart/form-data" method="post">
<input type="file" name="file">
<input type="submit" value="Submit">
</form>
</body>
</html>
Apache Commons FileUpload
在pom.xml文件中引入依赖Apache Commons FileUpload依赖:
<!-- commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
在AppConfig.java中声明一个名称为multipartResolver的CommonsMultipartResolver Bean。
@Configuration
@ComponentScan("io.github.nirvanafire")
public class AppConfig implements WebMvcConfigurer {
...
@Bean("multipartResolver")
public CommonsMultipartResolver commonsMultipartResolver() {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
return commonsMultipartResolver;
}
}
Servlet 3.0
在Servlet注册器中设置一个MultipartConfigElement,即在MyWebApplicationInitializer.java中添加如下代码:
private int MAX_UPLOAD_SIZE = 5 * 1024 * 1024;
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
...
System.out.println("---tmpdir: " + System.getProperty("java.io.tmpdir") + "---");
File uploadDirectory = new File(System.getProperty("java.io.tmpdir"));
/**
* MultipartConfigElement参数含义
* @param location the directory location where files will be stored (上传文件存储目录)
* @param maxFileSize the maximum size allowed for uploaded files(单文件上传大小限制)
* @param maxRequestSize the maximum size allowed for multipart/form-data requests(一个请求上传大小限制)
* @param fileSizeThreshold the size threshold after which files will (文件写入磁盘的阈值,可理解为每次读取文件大小)
*/
MultipartConfigElement multipartConfigElement = new MultipartConfigElement(uploadDirectory.getAbsolutePath(),
MAX_UPLOAD_SIZE, MAX_UPLOAD_SIZE * 2, MAX_UPLOAD_SIZE / 2);
registration.setMultipartConfig(multipartConfigElement);
}
在AppConfig.java中声明一个名称为multipartResolver的StandardServletMultipartResolver Bean。
@Configuration
@ComponentScan("io.github.nirvanafire")
public class AppConfig implements WebMvcConfigurer {
...
@Bean("multipartResolver")
public StandardServletMultipartResolver standardServletMultipartResolver() {
StandardServletMultipartResolver standardServletMultipartResolver = new StandardServletMultipartResolver();
return standardServletMultipartResolver;
}
}
小结
不论是FileUpload或是Servlet 3.0实现多部分解析功能,都需要在DispatcherServletSpring配置中声明一个名为multipartResolver的MultipartResolverbean(FileUpload声明CommonsMultipartResolver,Servlet 3.0声明StandardMultipartResolver),通过限定声明bean的名称(multipartResolver),限制项目中多部分解析仅有一种实现方式