【问题标题】:Problem with Spring FileUploadSpring FileUpload 的问题
【发布时间】:2011-04-14 10:18:21
【问题描述】:

我有以下代码块处理我在 Spring MVC Web 应用程序中使用的照片的文件上传。我正在使用 Spring MVC CommonsMultipartFileResolver 来处理文件上传。

if(model.getPhoto() != null){
    if(!model.getPhoto().isEmpty()){
        MultipartFile file = model.getPhoto();
        String fileName = file.getOriginalFilename();
        String filePath = baseDirectory + fileName;
        FileOutputStream fos = new FileOutputStream(filePath);
         try 
         {
            fos.write(file.getBytes());
            agentProfile.setPhotoUri(fileName);
         } 
         catch (IllegalStateException e) 
         {
            System.out.println(e);

         }
         finally   
         {
             fos.close();
         }
    }
}

在我的 app-servlet.xml 文件中,我有以下代码来配置 MultipartFile 解析器 bean。

 <bean id="multipartResolver"   class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
 </bean>

我在上传照片时遇到了一些随机问题。

1)如果我去上传一张较小的照片,大约3 kb左右,它会上传成功。

2)如果我要上传大一点的照片,它会在目录中创建文件,但大小为0字节,并会给出以下错误消息。

 java.lang.IllegalStateException: File has been moved - cannot be read again
org.springframework.web.multipart.commons.CommonsMultipartFile.getBytes(CommonsMultipartFile.java:112)
com.mmz.admin.mvc.controller.AddAgentController.processFinish(AddAgentController.java:145)
org.springframework.web.servlet.mvc.AbstractWizardFormController.validatePagesAndFinish(AbstractWizardFormController.java:642)
org.springframework.web.servlet.mvc.AbstractWizardFormController.processFormSubmission(AbstractWizardFormController.java:492)
org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:265)
org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:874)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:808)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:476)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:441)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

我尝试了几个不同的选项来配置 Multipart 解析器,例如将其切换为处理 CommonsMultipartFile 对象,而不是普通的 MultipartFile 对象,但没有任何改变。

我还尝试使用以下属性在 CommonsMultipartFileResolver bean 中手动配置最大上传大小。

 <property name="maxUploadSize" value="1024000000"/>  

也没有任何改变。我不确定 CommonsMultipartResolver 默认的可上传文件大小,但这不是我的问题。

有人告诉我,我遇到的问题是由于 spring 正在使用的 Multipart 解析器/处理程序中的问题。我最近有一篇关于同样问题的帖子,因为发现了新信息,所以想用新信息重新发布。旧帖可见CommonsMultipartFileResolver Problem

我觉得我已经检查了互联网上的几乎所有资源以查找其他文档,但无法找出问题所在。

请帮我弄清楚这是怎么回事,如果有更好、更简单的解决方案来探索这些选项,但如果可以的话,我更愿意继续使用我目前的方法找到解决办法。

编辑 注意-我一直在尝试上传不同尺寸的照片,我相信它允许我上传的限制约为 10Kb。任何大于 10Kb 的东西都会导致它中断并给我上面的错误。

【问题讨论】:

标签: java spring file-upload spring-mvc


【解决方案1】:

经过大量研究,我解决了我的问题。事实证明,您可以使用 CommonsMultipartFileResolver 上传的最大字节数没有设置默认限制。当然,您可以通过设置以下属性在 bean 中指定任何您想要的字节数。

<property name="maxUploadSize" value="99999999999"/>

还有一个属性 maxInMemorySize 允许您指定文件写入磁盘之前允许的最大大小。尽管这与最大上传大小的工作方式相同,但如果您不指定数量,则默认为 1024 字节。如果我尝试上传一个大文件,这将解释它的破坏。

为了允许上传超过 1024 字节的文件,您需要将 maxInMemorySize 值增加到您需要的任何值,如下所示...

这就是解决我的问题的原因。当我查看 CommonsFileUpload Documentation 的文档时,我了解到此属性默认为 1024。

您可以在CommonsFileUpload Documentation查看此文档

我希望这对任何人都有帮助,因为没有关于使用 CommonsMultipartFile 的很好的文档。

【讨论】:

  • 很好的发现,虽然我觉得这个默认设置不应该导致上传失败。我会向 Spring 男孩报告一个问题,看看他们对这个问题有什么看法。
  • 我会的,我会更深入地研究这个问题。令人惊讶的是,如果没有指定其他内容,他们会默认为 1024。
  • 根据你引用的链接,默认是10240字节(说明你之前的经验结果)。
  • 非常感谢您的回答!我也遇到了这些随机问题。您已经节省了数小时试图弄清楚的时间。干杯
【解决方案2】:

我注意到只有当文件超过 1024 字节时才会出现此错误并且您尝试读取文件两次。正如 CitadelCSAlum 所提到的,设置 maxInMemorySize = maxUploadSize 将解决此问题,但应牢记内存使用情况。如果内存是一个问题,另一种选择是在第一次读取时将多部分文件数据写入临时文件,并使用该文件进行后续读取。如果您不阅读两次,则不需要增加 maxInMemorySize。

【讨论】:

    【解决方案3】:

    您在问题中引用的异常指出:“文件已被移动 - 无法再次读取”。这是因为我们试图从多部分文件中多次读取输入流。

    我也曾经遇到过这个问题,就我而言,首先我验证了文件的内容,然后我尝试使用 Spring MultiPart 中的“transferTo”方法保存它。当我尝试使用“transferTo”方法时会出现此异常。这里我两次调用输入流。

    当文件太小时,我不会遇到这个问题。在“transferTo”方法中有一个“isAvailable”方法的内部调用。请按照下面的代码段:

        protected boolean More ...isAvailable() {
                // If in memory, it's available.
            if (this.fileItem.isInMemory()) {
                return true;
            }
            // Check actual existence of temporary file.
            if (this.fileItem instanceof DiskFileItem) {
                return ((DiskFileItem) this.fileItem).getStoreLocation().exists();
            }
            // Check whether current file size is different than original one.
            return (this.fileItem.getSize() == this.size);
        }
    

    链接:http://grepcode.com/file/repo1.maven.org/maven2/org.springframework/spring-web/3.2.1.RELEASE/org/springframework/web/multipart/commons/CommonsMultipartFile.java#CommonsMultipartFile.isAvailable%28%29

    观察:

    1. 如果它太小,弹簧将其保存在内存中,当我们请求文件时,它会从内存中检索。我们可以多次请求它,因为文件在内存中。

    2. 如果它足够大,Spring 会将它保存为一个我们不知道位置的临时文件,但是在我们读取 inputstream 一次之后,该文件可能会被 Spring 在内部删除。然后当我们第二次询问时,错误提示“无法再次读取”。

    所以我的解决方案是首先我必须使用“transferTo”方法将其保存在服务器位置,然后检索该本地文件以进行验证或任何其他第二次需要。

    我认为在“multipartResolver”bean 中增加“maxUploadSize”不好,因为如果文件太大会消耗更多内存。

    【讨论】:

    • 这并不能真正回答问题。如果您有其他问题,可以点击 提问。一旦你有足够的reputation,你也可以add a bounty引起更多的关注。
    • 我不同意这一点。在“CommonsMultipartFile”类中调用“getBytes”方法时会出现此异常。在我的例子中,我使用“transferTo”方法,在这两种情况下,它都会调用“isAvailable”方法。如果我们已经使用该多部分文件的输入流,则会发生此异常。所以我的解决方案是首先我们需要将该文件保存在服务器位置并让该文件进行任何验证。因为如果超过了这个限制,Spring 会将该文件存储在磁盘而不是内存中。当我们读取一次时,它将删除磁盘中的临时文件。但如果它太小,它将驻留在内存中。
    • 对此感到抱歉,鉴于您回答的措辞/格式,它看起来像是“我遇到了同样的问题”的评论。我撤回了我的反对票。
    • 我不完全同意你的说法,即不能两次读取多部分文件。你可以。当您尝试读取流(或传输它,这是相同的)请求处理完成后引发给定异常,例如在另一个线程中。 DispatcherServlet.doDispatch() 在处理请求后,当处理程序返回时执行多部分请求的清理(除非 Spring 知道请求是异步的,例如标记为 @Async)。因此,如果请求处理程序已将 MultipartFile 放入稍后将处理的队列 - 运气不好。
    猜你喜欢
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 2021-10-12
    • 1970-01-01
    • 2011-01-22
    • 2011-04-23
    • 2016-08-24
    相关资源
    最近更新 更多