处理multipart形式的数据
在处理文件上传之前,我们需要配置multipart解析器
配置multipart解析器
从Spring3.1开始,Spring提供了2个解析器。
- CommonsMultipartResolver
- StandardServletMultipartResolver:基于Servlet3.0容器。(始于Spring3.1)
通常,使用StandardServletMultipartResolver是优选的方案,但是如果使用servlet3.0之前的Servlet容器,或者使用Spring3.1之前,那么只能使用CommonsMultipartResolver。
配置StandardServletMultipartResolver
- 首先需要配置为bean
@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
- 然后需要做一些细节配置
有2种方式,在servlet初始化类中或xml。
在servlet初始化类配置
- 如果我们采用Servlet初始化类的方式来配置DispatcherServlet的话,这个初始化类应该 已经实现了WebApplicationInitializer,那我们可以在Servlet registration上调 用setMultipartConfig()方法,传入一个MultipartConfigElement实例。
DispatcherServlet ds = new DispatcherServlet();
Dynamic registration = context.addServlet("appServlet", ds);
registration.addMapping("/");
registration.setMultipartConfig(
new MultipartConfigElement("/tmp/spittr/uploads"));
- 如果我们配置DispatcherServlet的Servlet初始化类继承了Abstract AnnotationConfigDispatcherServletInitializer或AbstractDispatcher- ServletInitializer的话,我们要重写customizeRegistration方法。
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(
new MultipartConfigElement("/tmp/spittr/uploads"));
}
上面MultipartConfigElement的构造方法的参数是临时路径,除了这个参数,还有其他参数的构造器
- 上传文件的最大大小(单位是字节),默认是没有大小限制。
- 请求的最大大小(单位是字节),默认是没有大小限制。
- 文件大小达到多少时,会直接存放到临时路径中。默认是0,意思是所有的文件都存放到磁盘的临时路径中。
使用4个参数的demo如下
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(
new MultipartConfigElement("/tmp/spittr/uploads", 2097152, 4194304, 0));
}
限制上传文件的最大大小是2MB,请求的最大大小是4MB,所有文件都保存到磁盘的临时路径中。
在xml中配置
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/application-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<multipart-config>
<location>/tmp/spittr/uploads</location>
<max-file-size>2097152</max-file-size>
<max-request-size>4194304</max-request-size>
</multipart-config>
</servlet>
默认值和MultipartConfigElement一样,同样,是必须配置的。
配置CommonsMultipartResolver解析器
如果使用servlet3.0之前的容器或使用Spring3.1之前的版本,那么我们要使用CommonsMultipartResolver。
@Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
这时最简单的配置方式,和StandardServletMultipartResolver不同,CommonsMultipartResolver不需要强制配置临时路径。
也可以设置一些限制。
@Bean
public MultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads")); //设置临时路径
multipartResolver.setMaxUploadSize(2097152); //设置上传文件的最大大小
multipartResolver.setMaxInMemorySize(0); //设置内存大小
return multipartResolver;
}
CommonsMultipartResolver不能设置请求的最大大小。
处理multipart请求
我们在注册页面中添加上传图片的功能
<form method="post" enctype="multipart/form-data">
...
<label>profilePicture:</label>
<input type="file" accept="image/jpeg, image/png, image/gif" />
...
</form>
接着就是在控制器方法中获取图片参数,有3种方式:
- byte数组
- MultipartFile对象
- Part对象
我们需要在方法参数上使用注解@RequestPart。
使用byte[]数组方式接收
@RequestMapping(value="register", method=RequestMethod.POST)
public String processRegistration(
@RequestPart("profilePicture") byte[] profilePicture,
Spitter spitter, Errors errors) {
...
}
如果没有选择文件,那么这个数组为空,而不是Null。
byte[]数组功能有限,使用MultipartFile可以获取更多的信息,下面是使用MultipartFile接收
@RequestMapping(value="register", method=RequestMethod.POST)
public String processRegistration(
@RequestPart("profilePicture") MultipartFile multipartFile,
Spitter spitter, Errors errors) {
...
}
@RequestPath
- value属性:multipart/form-data请求中的参数名。
MultipartFile接口如下:
public interface MultipartFile extends InputStreamSource {
String getName();
@Nullable
String getOriginalFilename();
@Nullable
String getContentType();
boolean isEmpty();
long getSize();
byte[] getBytes() throws IOException;
InputStream getInputStream() throws IOException;
default Resource getResource() {
return new MultipartFileResource(this);
}
void transferTo(File var1) throws IOException, IllegalStateException;
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));
}
}
通过MultipartFile对象,我们不仅可以拿到文件的byte形式的数据,还能获取原始文件名、内容类型、大小,还有一个InputStream,可以用来将文件数据以流的方式进行处理。还有一个transferTo方法,能让我们可以将上传的文件保存到文件系统中。
在processRegistration方法中举例
profilePicture.transferTo(new File("/data/spittr/" + profilePicture.getOriginalFileName()));
以Part的形式接收文件
@RequestMapping(value="register", method=RequestMethod.POST)
public String processRegistration(
@RequestPart("profilePicture") Part profilePicture,
Spitter spitter, Errors errors) {
...
}
Part接口如下
package javax.servlet.http;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
public interface Part {
InputStream getInputStream() throws IOException;
String getContentType();
String getName();
String getSubmittedFileName();
long getSize();
void write(String var1) throws IOException;
void delete() throws IOException;
String getHeader(String var1);
Collection<String> getHeaders(String var1);
Collection<String> getHeaderNames();
}
和MultipartFile的方式类似。
注意: 如果使用Part类型接收文件,那么不需要配置MultipartResolver。只有使用MultipartFile,才需要配置MultipartResolver。