重要提示:这个问题对于任何高于3.0.4的 Spring 版本完全没有用,因为该线程中讨论的问题很久以前就已在该版本中修复,并且在 Spring 的后续版本中不再可重现。
我正在使用 Spring 3.0.2 版。我需要使用multiple="multiple"
文件浏览器的属性上传多个文件,例如,
<input type="file" id="myFile" name="myFile" multiple="multiple"/>
(而不是使用多个文件浏览器,就像这个答案所说的那样,它确实有效,我试过了)。
尽管除非使用适当的 jQuery 插件/小部件,否则没有任何版本的 Internet Explorer 支持这种方法,但我现在并不关心它(因为大多数其他浏览器都支持这种方法)。
这适用于公共文件上传,但除了使用RequestMethod.POST
和RequestMethod.GET
方法之外,我还想在它们自己的适当位置使用 Spring 支持RequestMethod.PUT
和建议的其他请求方法。RequestMethod.DELETE
为此,我已经配置了 Spring,HiddenHttpMethodFilter
正如这个问题所表明的那样。
但即使在文件浏览器中选择了多个文件,它一次也只能上传一个文件。在 Spring 控制器类中,方法映射如下。
@RequestMapping(method={RequestMethod.POST}, value={"admin_side/Temp"})
public String onSubmit(@RequestParam("myFile") List<MultipartFile> files, @ModelAttribute("tempBean") TempBean tempBean, BindingResult error, Map model, HttpServletRequest request, HttpServletResponse response) throws IOException, FileUploadException {
for (MultipartFile file : files) {
System.out.println(file.getOriginalFilename());
}
}
即使请求参数@RequestParam("myFile") List<MultipartFile> files
是一种List
类型MultipartFile
(它一次只能有一个文件)。
我可以在此博客上找到一种可能适用于多个文件的策略。我已经仔细检查过了。
解决方案 2 – 使用原始请求部分下方的解决方案说,
但是,如果客户坚持使用相同的表单输入名称,例如“files[]”或“files”,然后用多个文件填充该名称,则需要进行如下小技巧。如上所述,如果 Spring 2.5 多次检测到类型文件的相同表单输入名称,则会引发异常。CommonsFileUploadSupport –抛出该异常的类不是最终的,并且抛出该异常的方法受到保护,因此使用继承和子类化的奇迹可以简单地修复/修改逻辑,如下所示。我所做的更改实际上是一个单词代表一种方法调用,它使我们能够以相同的表单输入名称接收多个文件。
它试图覆盖该方法
protected MultipartParsingResult parseFileItems(List fileItems, String encoding){}
CommonsFileUploadSupport
通过扩展类来实现抽象类,CommonsMultipartResolver
例如,
package multipartResolver;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.apache.commons.fileupload.FileItem;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
public final class MultiCommonsMultipartResolver extends CommonsMultipartResolver {
public MultiCommonsMultipartResolver() {}
public MultiCommonsMultipartResolver(ServletContext servletContext) {
super(servletContext);
}
@Override
@SuppressWarnings("unchecked")
protected MultipartParsingResult parseFileItems(List fileItems, String encoding) {
Map<String, MultipartFile> multipartFiles = new HashMap<String, MultipartFile>();
Map multipartParameters = new HashMap();
// Extract multipart files and multipart parameters.
for (Iterator it = fileItems.iterator(); it.hasNext();) {
FileItem fileItem = (FileItem) it.next();
if (fileItem.isFormField()) {
String value = null;
if (encoding != null) {
try {
value = fileItem.getString(encoding);
} catch (UnsupportedEncodingException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not decode multipart item '" + fileItem.getFieldName()
+ "' with encoding '" + encoding + "': using platform default");
}
value = fileItem.getString();
}
} else {
value = fileItem.getString();
}
String[] curParam = (String[]) multipartParameters.get(fileItem.getFieldName());
if (curParam == null) {
// simple form field
multipartParameters.put(fileItem.getFieldName(), new String[]{value});
} else {
// array of simple form fields
String[] newParam = StringUtils.addStringToArray(curParam, value);
multipartParameters.put(fileItem.getFieldName(), newParam);
}
} else {
// multipart file field
CommonsMultipartFile file = new CommonsMultipartFile(fileItem);
if (multipartFiles.put(fileItem.getName(), file) != null) {
throw new MultipartException("Multiple files for field name [" + file.getName()
+ "] found - not supported by MultipartResolver");
}
if (logger.isDebugEnabled()) {
logger.debug("Found multipart file [" + file.getName() + "] of size " + file.getSize()
+ " bytes with original filename [" + file.getOriginalFilename() + "], stored "
+ file.getStorageDescription());
}
}
}
return new MultipartParsingResult(multipartFiles, multipartParameters);
}
}
发生的事情是方法中的最后一行parseFileItems()
(return 语句),即
return new MultipartParsingResult(multipartFiles, multipartParameters);
导致编译时错误,因为第一个参数multipartFiles
是由Map
实现的类型,但实际上,它需要一个类型的参数HashMap
MultiValueMap<String, MultipartFile>
它是抽象类内部静态类的构造函数CommonsFileUploadSupport
,
public abstract class CommonsFileUploadSupport {
protected static class MultipartParsingResult {
public MultipartParsingResult(MultiValueMap<String, MultipartFile> mpFiles, Map<String, String[]> mpParams) {}
}
}
原因可能是 - 这个解决方案是关于 Spring 2.5 版的,我使用的是 Spring 3.0.2 版,这可能不适合这个版本。
但是,我尝试以各种方式替换 ,Map
例如MultiValueMap
以下代码段中显示的方式,
MultiValueMap<String, MultipartFile>mul=new LinkedMultiValueMap<String, MultipartFile>();
for(Entry<String, MultipartFile>entry:multipartFiles.entrySet()) {
mul.add(entry.getKey(), entry.getValue());
}
return new MultipartParsingResult(mul, multipartParameters);
但没有成功。我不确定如何替换Map
,MultiValueMap
甚至这样做也可以。完成此操作后,浏览器显示 Http 响应,
HTTP 状态 400 -
类型状态报告
信息
描述客户端发送的请求语法错误()。
Apache Tomcat/6.0.26
我试图尽可能缩短问题,并且我没有包含不必要的代码。
在配置了 Spring 之后,如何才能上传多个文件HiddenHttpMethodFilter
?
该博客表明这是一个长期存在的高优先级错误。
如果没有关于版本 3.0.2(3 或更高版本)的解决方案,那么我必须永远禁用 Spring 支持并继续使用commons-fileupolad,正如该博客上的第三个解决方案所建议的那样,永远省略 PUT、DELETE 和其他请求方法.
parseFileItems()
对类内方法中的代码进行很少的更改MultiCommonsMultipartResolver
可能会使其上传多个文件,但我的尝试无法成功(再次使用 Spring 版本 3.0.2(3 或更高版本))。