我们知道web上传文件form表单要加enctype=“multipart/form-data”,而SpringMVC提供了MultipartResolver接口来让实现文件流解析。而SpringMVC提供了两种解析器
CommonsMultipartResolver
我们点开这个文件解析器的源码发现继承了CommonsFileUploadSupport,而再点开这类support抽象类,发现里面是对fileupload的封装,使用过struts框架的同学肯定知道struts时有smartupload和fileUpload两个工具包。所以使用CommonsMultipartResolver实际就是用fileupload,这里要引用
commons-fileupload、commons-io这两个工具包。然后这里有两种配置:
1.spring-mvc.xml定义一个类型为CommonsMultipartResolver、id为multipartResolver的bean ,设置文件上传的最大字节数
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="${web.maxUploadSize}" />
</bean>
有的同学会问,这样为什么就可以了呢,用其他id名称可以不,这里明确说如果这里配置明确不可以,我们知道通常我们要在web.xml里引用SpringMVC的默认servlet,类似下面
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
其中servlet-name随便定义,spring-mvc.xml文件名随便定义,我们点开DispatcherServlet源码发现如下有MultipartResolver初始化,
/**
* Initialize the MultipartResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* no multipart handling is provided.
*/
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
}
}
}
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
这里会到上下文中找id为multipartResolver的bean
2. web.xml定义一个MultipartFilter,我们点击MultipartResolver这个接口,发现有个MultipartFilter过滤器引用了他,而该过滤器在springmvc默认配置里还没引用,我们点击源码
public class MultipartFilter extends OncePerRequestFilter {
public static final String DEFAULT_MULTIPART_RESOLVER_BEAN_NAME = "filterMultipartResolver";
private final MultipartResolver defaultMultipartResolver = new StandardServletMultipartResolver();
private String multipartResolverBeanName = "filterMultipartResolver";
public MultipartFilter() {
}
public void setMultipartResolverBeanName(String multipartResolverBeanName) {
this.multipartResolverBeanName = multipartResolverBeanName;
}
protected String getMultipartResolverBeanName() {
return this.multipartResolverBeanName;
}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
MultipartResolver multipartResolver = this.lookupMultipartResolver(request);
HttpServletRequest processedRequest = request;
if (multipartResolver.isMultipart(request)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Resolving multipart request [" + request.getRequestURI() + "] with MultipartFilter");
}
processedRequest = multipartResolver.resolveMultipart(request);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Request [" + request.getRequestURI() + "] is not a multipart request");
}
try {
filterChain.doFilter((ServletRequest)processedRequest, response);
} finally {
if (processedRequest instanceof MultipartHttpServletRequest) {
multipartResolver.cleanupMultipart((MultipartHttpServletRequest)processedRequest);
}
}
}
protected MultipartResolver lookupMultipartResolver(HttpServletRequest request) {
return this.lookupMultipartResolver();
}
protected MultipartResolver lookupMultipartResolver() {
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
String beanName = this.getMultipartResolverBeanName();
if (wac != null && wac.containsBean(beanName)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using MultipartResolver '" + beanName + "' for MultipartFilter");
}
return (MultipartResolver)wac.getBean(beanName, MultipartResolver.class);
} else {
return this.defaultMultipartResolver;
}
}
}
发现一个叫multipartResolverBeanName的参数,我们知道如何在javaweb项目里配置一个过滤器,需要web,xml定义
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
<init-param>
<param-name>multipartResolverBeanName</param-name>
<param-value>commonsMultipartResolver</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
其中url-pattern只设置你项目里文件上传的路径,发现这里就可以随便定义文件上传解析器的id了,但是我们知道filter是优先于servlet初始化的,所以在DispatcherServlet初始化时加载的spring-mvc.xml定义的commonsMultipartResolver是找不到的,所以需要在context里加载的配置文件里定义,分别如下
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring-context.xml</param-value>
</context-param>
spring-context.xml有下面定义
<bean id="commonsMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="${web.maxUploadSize}" />
</bean>
StandardServletMultipartResolver
根据名字知道这个是标准servlet文件解析器,其中配置有两种配置跟上面类似,但是不需要依赖包,点开源码:
package org.springframework.web.multipart.support;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
public class StandardServletMultipartResolver implements MultipartResolver {
private boolean resolveLazily = false;
public StandardServletMultipartResolver() {
}
public void setResolveLazily(boolean resolveLazily) {
this.resolveLazily = resolveLazily;
}
public boolean isMultipart(HttpServletRequest request) {
if (!"post".equals(request.getMethod().toLowerCase())) {
return false;
} else {
String contentType = request.getContentType();
return contentType != null && contentType.toLowerCase().startsWith("multipart/");
}
}
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}
public void cleanupMultipart(MultipartHttpServletRequest request) {
try {
Iterator var2 = request.getParts().iterator();
while(var2.hasNext()) {
Part part = (Part)var2.next();
if (request.getFile(part.getName()) != null) {
part.delete();
}
}
} catch (Exception var4) {
LogFactory.getLog(this.getClass()).warn("Failed to perform cleanup of multipart items", var4);
}
}
}
发现这个更简单,而是利用了javax.servlet.http.Part,这个servlet3.0以上才有的类,也就说必须web容器支持servlet3.03.0以上,如下也有三种配置,第一种第二种类似上面
- spring-mvc.xml定义类型是StandardServletMultipartResolver、id为的multipartResolver的bean ,设置文件上传的最大字节数
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
<property name="maxUploadSize" value="${web.maxUploadSize}" />
</bean>
2.web.xml定义一个MultipartFilter,spring-context.xml定义一个类型为定义类型是StandardServletMultipartResolver的bean,
<bean id="standardServletMultipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
<property name="maxUploadSize" value="${web.maxUploadSize}" />
</bean>
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
<init-param>
<param-name>multipartResolverBeanName</param-name>
<param-value>standardServletMultipartResolver</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 用multipart-config标签或者MultipartConfig注解,标签是web.xml,如下
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>SpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring-mvc.xml</param-value>
</init-param>
<multipart-config>
<location>/tmp</location>
<max-file-size>5242880</max-file-size><!--5MB-->
<max-request-size>20971520</max-request-size><!--20MB-->
<file-size-threshold>0</file-size-threshold>
</multipart-config>
</servlet>
标签如下用法
@MultipartConfig(location="/tmp",maxFileSize=5242880,maxRequestSize=20971520,fileSizeThreshold=0)//标识Servlet支持文件上传
public class UploadServlet extends HttpServlet {
我们在SpringMVC项目里可以继承DispatcherServlet,然后重写它方法
结语
到此我们五种使用清楚了,发现其中有四种配置类似,用了两种解析器。