StandardServletMultipartResolver和CommonsMultipartResolver。前者使用了Servlet3.0标准的上传方式,后者使用了Apache的commons-fileupload。
1. StandardServletMultipartResolver
StandardServletMultipartResolver使用了Servlet3.0标准的上传方式,在Servlet3.0中上传文件非常简单,只需要调用request的getParts方法就可以获取所有上传的文件。
获取到Part后直接调用它到write(saveFileName)方法就可以将文件保存为以saveFileName为文件名的文件,也可以调用getInputStream获取InputStream。
public class StandardServletMultipartResolver implements MultipartResolver {
private boolean resolveLazily = false;
/**
*设置在时是否惰性解决多部分请求
*文件或参数访问。
*
默认为“false”,立即分解多部分元素,抛出
*调用{@link #resolveMultipart}时对应的异常。
*对于懒惰的多部分解析,将其切换为“true”,抛出解析异常
*一旦应用程序试图获得多部分文件或参数。
*/
public void setResolveLazily(boolean resolveLazily) {
this.resolveLazily = resolveLazily;
}
@Override
public boolean isMultipart(HttpServletRequest request) {
return StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/");
}
@Override
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}
@Override
public void cleanupMultipart(MultipartHttpServletRequest request) {
if (!(request instanceof AbstractMultipartHttpServletRequest) ||
((AbstractMultipartHttpServletRequest) request).isResolved()) {
// To be on the safe side: explicitly delete the parts,
// but only actual file parts (for Resin compatibility)
try {
for (Part part : request.getParts()) {
if (request.getFile(part.getName()) != null) {
part.delete();
}
}
}
catch (Throwable ex) {
LogFactory.getLog(getClass()).warn("Failed to perform cleanup of multipart items", ex);
}
}
}
}
resolveMultipart 方法返回了StandardMultipartHttpServletRequest:
public StandardMultipartHttpServletRequest(HttpServletRequest request, boolean lazyParsing)
throws MultipartException {
super(request);
if (!lazyParsing) {
parseRequest(request);
}
}
private void parseRequest(HttpServletRequest request) {
try {
Collection<Part> parts = request.getParts();
this.multipartParameterNames = new LinkedHashSet<>(parts.size());
MultiValueMap<String, MultipartFile> files = new LinkedMultiValueMap<>(parts.size());
for (Part part : parts) {
String headerValue = part.getHeader(HttpHeaders.CONTENT_DISPOSITION);
ContentDisposition disposition = ContentDisposition.parse(headerValue);
String filename = disposition.getFilename();
if (filename != null) {
if (filename.startsWith("=?") && filename.endsWith("?=")) {
filename = MimeDelegate.decode(filename);
}
files.add(part.getName(), new StandardMultipartFile(part, filename));
}
else {
this.multipartParameterNames.add(part.getName());
}
}
setMultipartFiles(files);
}
catch (Throwable ex) {
handleParseFailure(ex);
}
}
大概思路就是通过request的getParts方法获取所有Part,然后使用它们创建出File并保存到对应的属性;
再回过头来看isMultipart方法中首先判断是不是post请求,如果是则再检查contentType是不是以“multipart/”开头,如果也是则认为是上传请求。
cleanupMultipart方法删除了缓存。
2. CommonsMultipartResolver
CommonsMultipartResolver使用了commons-fileupload来完成具体的上传操作。
在CommonsMultipartResolver中,判断是不是上传请求的isMultipart,这将交给commons-fileupload的ServletFileUpload类完成
@Override
public boolean isMultipart(HttpServletRequest request) {
return ServletFileUpload.isMultipartContent(request);
}
实际处理request的方法是resolveMultipart:
@Override
public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
Assert.notNull(request, "Request must not be null");
if (this.resolveLazily) {
//是懒处理,那么就使用DefaultMultipartHttpServletRequest
return new DefaultMultipartHttpServletRequest(request) {
@Override
protected void initializeMultipart() {
MultipartParsingResult parsingResult = parseRequest(request);
setMultipartFiles(parsingResult.getMultipartFiles());
setMultipartParameters(parsingResult.getMultipartParameters());
setMultipartParameterContentTypes(parsingResult.getMultipartParameterContentTypes());
}
};
}
else {
//如果不是,则先调用parseRequest方法来处理request
MultipartParsingResult parsingResult = parseRequest(request);
return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
}
}
虽然有两种处理方法,但都是将Request转换为DefaultMultipartHttpServletRequest类型,而且都使用parseRequest方法进行处理。
这里我没有导入具体的包,所以感兴趣的可以导入commons包了解一下。