【问题标题】:Uploading multiple files using Spring MVC 3.0.2 after HiddenHttpMethodFilter has been enabled启用 HiddenHttpMethodFilter 后使用 Spring MVC 3.0.2 上传多个文件
【发布时间】:2012-12-03 15:47:20
【问题描述】:

重要提示: 这个问题对于任何高于 3.0.4 的 Spring 版本完全没有用,因为这个线程中讨论的问题在那个版本中一直是 fixed在 Spring 的后续版本中不再可重现。


我使用的是 Spring 3.0.2 版。我需要使用文件浏览器的multiple="multiple" 属性上传多个文件,例如,

<input type="file" id="myFile" name="myFile" multiple="multiple"/>

(而不是像this answer 所说的那样使用多个文件浏览器,它确实有效,我试过了)。

尽管没有任何版本的 Internet Explorer 支持这种方法,除非使用了适当的 jQuery 插件/小部件,但我现在并不关心它(因为大多数其他浏览器都支持这种方法)。

这适用于commons fileupload,但除了使用RequestMethod.POSTRequestMethod.GET 方法之外,我还想在它们自己的适当位置使用Spring 支持和建议的其他请求方法,例如RequestMethod.PUTRequestMethod.DELETE .为此,我使用HiddenHttpMethodFilter 配置了Spring,正如this question 所指示的那样。

一次只能上传一个文件,即使在文件浏览器中选择了多个文件。在 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&lt;MultipartFile&gt; filesList 类型为MultipartFile(它一次只能有一个文件)。


我可以找到一种可能适用于多个文件on this blog 的策略。我已经仔细研究过了。

解决方案部分解决方案2 - 使用原始请求说,

如果客户坚持使用相同的表单输入名称,例如 作为“文件[]”或“文件”,然后用多个填充该名称 文件,然后需要进行如下的小修改。如上所述,春天 如果多次检测到类型文件的相同表单输入名称,2.5 将引发异常。 CommonsFileUploadSupport - 抛出的类 该异常不是最终的,method 会引发该异常 受到保护,因此使用继承和子类化的奇迹 可以简单地修复/修改逻辑如下。改变 I've made 实际上是一个词代表一种方法调用 这使我们能够在同一个表单下接收多个文件 输入名称。

它试图覆盖该方法

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);
    }
}

发生的情况是方法@​​987654359@(返回语句)的最后一行,即

return new MultipartParsingResult(multipartFiles, multipartParameters);

导致编译时错误,因为第一个参数multipartFilesMap 实现的Map 类型HashMap 但实际上它需要一个类型的参数 MultiValueMap&lt;String, MultipartFile&gt; p>

是抽象类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);

但没有成功。我不确定如何用MultiValueMap 替换Map,即使这样做也可以。完成此操作后,浏览器显示 Http 响应,

HTTP 状态 400 -

输入状态报告

消息

描述客户端发送的请求语法错误 ()。

Apache Tomcat/6.0.26


我已尝试尽可能缩短问题,并且没有包含不必要的代码。

Spring 配置了HiddenHttpMethodFilter 后,如何才能上传多个文件?

该博客表明这是一个长期存在的高优先级错误。

如果没有关于版本 3.0.2(3 或更高版本)的解决方案,那么我必须永远禁用 Spring 支持并继续使用 commons-fileupolad,正如该博客上的第三个解决方案所建议的那样,省略了 PUT、DELETE 和其他永远请求方法。


MultiCommonsMultipartResolver 类中的 parseFileItems() 方法中的代码进行很少的更改可能会使其上传多个文件,但我的尝试无法成功(再次使用 Spring 版本 3.0.2(3 或更高版本) )。

【问题讨论】:

  • 博文中提到的Jira issue自3.0.4版本以来已修复,可以尝试升级吗?
  • @RC - 感谢您的链接。我有一个已完成一半以上的大型应用程序。更改框架可能需要在许多地方更改代码,所以我只能为未来的项目考虑更高版本(我应该在开始之前就知道它)。谢谢。
  • 3.0.2 到 3.0.4 是一个小升级(如果我查看版本号,主要是错误修复),所以它应该是无痛的。如果可行,您应该尝试并继续努力
  • 我现在已将 Spring 版本从 3.0.2 升级到 3.2.0,其中问题的问题可以正常工作,但如果有人有这个问题的解决方案,将不胜感激。
  • 也许我不清楚。我要求文件的原因是查看信息如何到达多部分数据。这样您就可以排除简单正则表达式解析的问题,并且可以在不使用常见文件上传的情况下获取所有文件和变量。因为肯定不会收到多个文件。

标签: spring spring-mvc file-upload spring-3


【解决方案1】:

为了在一个请求中上传多个文件,我使用了以下代码:

我有这样的jsp:

<p>Select files to upload. Press Add button to add more file inputs.</p>
<table>
    <tr>
        <td><input name="files" type="file" multiple="true"/></td>
    </tr>
    <tr>
        <td><input name="files" type="file" multiple="true"/></td>
    </tr>
</table>
<br/><input type="submit" value="Upload" />

文件上传类 bean:

import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class FileUploadForm {

    private CommonsMultipartFile [] files;

    public CommonsMultipartFile[] getFiles() {
        return files;
    }

    public void setFiles( CommonsMultipartFile[] files ) {
        this.files = files;
    }
}

控制器:

@Controller
@RequestMapping("/upload")
public class FileUploadController {

    @RequestMapping(method = RequestMethod.GET)
    public String displayForm(ModelMap modelMap) {
        modelMap.addAttribute( new FileUploadForm() );
        return "uploadForm.jsp";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String save(FileUploadForm uploadForm) {
        CommonsMultipartFile[] files = uploadForm.getFiles();
        if(files != null && files.length != 0) {
            for(MultipartFile file : files) {
                System.out.println( file.getOriginalFilename() );
            }
        }
        return "success.jsp";
    }
}

此代码允许在一个请求中上传多个文件, 并且可以为每个文件获取CommonsMultipartFile 的实例。

【讨论】:

  • 是的,这是上传多个文件的方式,我用来上传多个文件的技术与您展示的技术没有什么不同,但它不适用于 Spring 框架我之前使用的 3.0.2(或更低)。其中,有一个文件被上传(通常是从文件浏览中选择的文件列表中的第一个)。你说的是这个版本吗?在这个版本中它对你有用吗?我敢肯定,这个版本的 Spring 不应该发生这种情况,对吧?最欢迎答复。谢谢。
【解决方案2】:

问题中提到的问题是 fixed 从 Spring 3.0.4 开始。因此,如果您碰巧使用该版本或更高版本(是的,现在是 4.x.x),您将不再需要阅读此问题/答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    相关资源
    最近更新 更多