《看透springMvc源代码分析与实践》学习笔记
SpringMVC 版本 4.1.5.RELEASE
MultipartResolver
MultipartResolver
用于处理文件上传,它的接口定义如下:
public interface MultipartResolver {
//判断request是否为文件上传请求
boolean isMultipart(HttpServletRequest request);
//将 HttpServletRequest 转换为 MultipartHttpServletRequest
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException;
//清空: 入参是MultipartHttpServletRequest
void cleanupMultipart(MultipartHttpServletRequest request);
}
MultipartResolver有两个实现类:
StandardServletMultipartResolver
: 使用Servlet3.0标准的上传方式,将HttpServletRequest
转换为StandardMultipartHttpServletRequest
。CommonsMultipartResolver
: 使用Apache的common-fileupload,将HttpServletRequest
转换为DefaultMultipartHttpServletRequest
。
MultipartHttpServletRequest
文件上传处理过程中使用的是MultipartHttpServletRequest
,它继承自接口MultipartRequest
.
SpringMVC提供了两种实现:StandardMultipartHttpServletRequest
和DefaultMultipartHttpServletRequest
,
他们有着同一个父类AbstractMultipartHttpServletRequest
,MultipartHttpServletRequest接口定义的方法基本都在AbstractMultipartHttpServletRequest
中实现。
AbstractMultipartHttpServletRequest
//org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest
public abstract class AbstractMultipartHttpServletRequest extends HttpServletRequestWrapper implements MultipartHttpServletRequest {
//注意: MultiValueMap 等价于 Map<String ,List<MultipartFile>>
private MultiValueMap<String, MultipartFile> multipartFiles;
//对象自身持有了 HttpServletRequest ;
protected AbstractMultipartHttpServletRequest(HttpServletRequest request) {
super(request);
}
//上传时:file文件对应form表单的key(不是file自身的属性name)
@Override
public Iterator<String> getFileNames() {
return getMultipartFiles().keySet().iterator();
}
@Override
public MultipartFile getFile(String name) {
//由于可能上传多个文件, 这里范湖first
return getMultipartFiles().getFirst(name);
}
//根据form表单key, 获取文件列表
@Override
public List<MultipartFile> getFiles(String name) {
List<MultipartFile> multipartFiles = getMultipartFiles().get(name);
if (multipartFiles != null) {
return multipartFiles;
}else {
return Collections.emptyList();
}
}
@Override
public Map<String, MultipartFile> getFileMap() {
return getMultipartFiles().toSingleValueMap();
}
@Override
public MultiValueMap<String, MultipartFile> getMultiFileMap() {
return getMultipartFiles();
}
//初始化时,set该属性
protected final void setMultipartFiles(MultiValueMap<String, MultipartFile> multipartFiles) {
this.multipartFiles = new LinkedMultiValueMap<String, MultipartFile>(Collections.unmodifiableMap(multipartFiles));
}
}
StandardServletMultipartResolver
StandardServletMultipartResolver
使用了Servlet3.0标准的上传方式,
通过request的contentType是否以"multipart/"
开头判断是否为文件上传请求,它将HttpServletRequest
转换为StandardMultipartHttpServletRequest
。
//org.springframework.web.multipart.support.StandardServletMultipartResolver
public class StandardServletMultipartResolver implements MultipartResolver {
private boolean resolveLazily = false;
//判断是 isMultipart
@Override
public boolean isMultipart(HttpServletRequest request) {
if (!"post".equals(request.getMethod().toLowerCase())) {
return false;
}
String contentType = request.getContentType();
return (contentType != null && contentType.toLowerCase().startsWith("multipart/"));
}
//将HttpServletRequest 转换为 StandardMultipartHttpServletRequest
@Override
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}
@Override
public void cleanupMultipart(MultipartHttpServletRequest request) {
for (Part part : request.getParts()) {
if (request.getFile(part.getName()) != null) {
part.delete();
}
}
}
}
CommonsMultipartResolver
CommonsMultipartResolver
使用了commons-fileupload来完成具体的上传操作。
它使用ServletFileUpload来判断是否为文件上传请求:
//使用ServletFileUpload来判断是否为文件上传请求
@Override
public boolean isMultipart(HttpServletRequest request) {
return (request != null && ServletFileUpload.isMultipartContent(request));
}
,resolveMultipart:将HttpServletRequest 转换为 DefaultMultipartHttpServletRequest
使用MultipartResolver
配置
web.xml
: DispatchServlet添加<multipart-config/>
配置。application-mvc.xml
:
<!-- 注意:bean id 必须为 multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</bean>
运行结果