【问题标题】:File Image to Servlet Fails文件映像到 Servlet 失败
【发布时间】:2013-10-09 00:39:48
【问题描述】:

我正在尝试将图像上传到 servlet,但在自动化测试期间每隔一段时间,它就会静默失败。

你们知道这是什么原因吗?

这是服务器上的代码:

    @ResponseBody
    @RequestMapping(method = RequestMethod.POST)
    public String upload(HttpServletRequest request) throws Exception {
     BufferedImage image = null;

     @SuppressWarnings("unchecked")
     List<FileItem> items = new ServletFileUpload(
           new DiskFileItemFactory()).parseRequest(request);

    Logger.log(LogLevel.INFO, "Upload contains " + items.size()
            + " items.");
    int i = 0;
    for (FileItem item : items) {
        Logger.log(LogLevel.INFO, "\tItem " + (i++) + ". Name:\t"
                + item.getName() + ", Type:\t" + item.getContentType());

        // File is of type "file"
        if (!item.isFormField()) {
            InputStream inputStream = null;
            try {
                inputStream = item.getInputStream();
                if (inputStream.available() == 0) {
                    Logger.log(LogLevel.WARN,
                            "Item shows file type, but no bytes are available");
                }
                image = ImageIO.read(inputStream);
                if (image != null) {
                    break;
                }
            } catch (Exception e) {
                Logger.log(LogLevel.ERROR,
                        "There was an error reading the image. "
                                + ExceptionUtils.getFullStackTrace(e));
                throw new Exception("image provided is not a valid image");
            } finally {
                if (inputStream != null) {
                    IOUtils.closeQuietly(inputStream);
                }
            }
        }
    }

     if (image == null) {
        Logger.log(LogLevel.ERROR, "Image was supposedly read correctly, but was null afterwards");
        throw new Exception("Image provided could not be read");
     }

     //do stuff with image
     ...
    }

这是测试:

 public void testImageUpload throws Exception {
    HttpPost httppost = new HttpPost("path/to/endpoint");
    File file=new File(imgLoc);
    FileBody bin = new FileBody(file);
    StringBody comment = new StringBody("Filename: " + file);

    MultipartEntity reqEntity = new MultipartEntity();
    reqEntity.addPart("upload-file", bin);
    reqEntity.addPart("comment", comment);
    httppost.setHeader("Accept", "application/json");
    httppost.setHeader("Connection","Keep-Alive");
    httppost.setEntity(reqEntity);
    HttpResponse response =testClient.getClient().execute(httppost);
    imgResponse=response.getStatusLine().toString();
    System.out.println(imgResponse);
    BufferedReader reader = new BufferedReader(
           new InputStreamReader(response.getEntity().getContent()));
    String line;
    while ((line = reader.readLine()) != null){
       output = output + " " +line;}
    System.out.println("Image Response: "+output);
}

这是服务器失败时的输出:

2013/10/02 05-53-32,287::LOG:INFO[com.example#upload:L130 -- Upload contains 2 items.]
2013/10/02 05-53-32,288::LOG:INFO[com.example#upload:L133 --        Item 0. Name:   Dog.jpg, Type:  application/octet-stream]
2013/10/02 05-53-32,288::LOG:WARN[com.example#upload:L140 -- Item shows file type, but no bytes are available]
2013/10/02 05-53-32,289::LOG:INFO[com.example#upload:L133 --        Item 1. Name:   null, Type:     text/plain; charset=ISO-8859-1]
2013/10/02 05-53-32,290::LOG:ERROR[com.example#upload:L159 -- Image was supposedly read correctly, but was null afterwards]

我们从图片上传中捕获异常,并将响应代码 422 发送回客户端,因此在测试中,我们得到imgResponse==422,这是一个失败案例。

注意:这只发生在有时您运行测试。

【问题讨论】:

  • 您能否提供可编译和可运行的代码以及您正在使用的示例上传?
  • @xwoker:仅供参考,it's called SSCCE
  • @Jason,你能解释一下if (image != null) { break; } 部分吗?
  • 我不确定哪个文件元素是图像,所以我们遍历文件直到我们可以解析一个。我们只希望每次上传一张图片。
  • @AndreaLigios 是的,好的老式 SSCCE。很高兴知道它还在。查看大多数“我的代码有什么问题”的问题,您会认为它以某种方式丢失在太空中。也许它应该从“如何提问”SO页面链接......

标签: java servlets spring-mvc


【解决方案1】:

您的内容类型似乎是 application/octet-stream。请在您的请求中添加以下 Header 并尝试一下

("Content-Type", "multipart/form-data");

【讨论】:

  • 会尝试并让您知道。它有时会起作用,所以如果它是标题就很奇怪。
【解决方案2】:

您正在使用InputStream#available。正如文档所述,这是可以从流中读取而不会阻塞的字节数。现在,TCP 输入流中可用的字节数取决于数据包的大小以及您的请求在它们之间的分割方式(以及更多其他因素)。

如果您的意图是始终完整读取流,请忘记 available() 方法,只需将其读取到流结束即可。

【讨论】:

  • 我使用available() 作为检查,但我使用image = ImageIO.read(inputStream); 读取图像。
  • 为了这个特定的测试,我会尝试将输入流读入 ByteArrayOutputStream 并在将字节缓冲区传递给 ImageIO 之前检查它是否真的是零长度。这至少应该可以帮助您找到问题所在。
【解决方案3】:

这里是使用 Apache Commons FileUpload 上传文件的逐步配置:

1.为以下组件添加依赖 jar。这是 maven 依赖项:

pom.xml

 <dependencies>
     <!-- Spring 3 MVC  -->
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-webmvc</artifactId>
         <version>3.2.4.RELEASE</version>
     </dependency>
     <!-- Apache Commons file upload  -->
     <dependency>
         <groupId>commons-fileupload</groupId>
         <artifactId>commons-fileupload</artifactId>
         <version>1.2.2</version>
     </dependency>
     <!-- Apache Commons IO -->
     <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-io</artifactId>
         <version>1.3.2</version>
     </dependency>
     <!-- JSTL for c: tag -->
     <dependency>
         <groupId>jstl</groupId>
         <artifactId>jstl</artifactId>
         <version>1.2</version>
     </dependency>
 </dependencies>

如果您不使用 maven,请在线从 maven 存储库下载相应的 jar。

2。创建 FileUploadForm 模型

FileUploadForm.java

import java.util.List;
import org.springframework.web.multipart.MultipartFile;

public class FileUploadForm {

    private List<MultipartFile> files;

    //Getter and setter methods
}

3.将解析器添加到 MVC 配置文件

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

    <!-- one of the properties available; the maximum file size in bytes -->
    <property name="maxUploadSize" value="100000"/>
</bean>

4.编写 FileUploadController

文件上传控制器.java

@Controller
public class FileUploadController {
     
    @RequestMapping(value = "/show", method = RequestMethod.GET)
    public String displayForm() {
        return "file_upload_form";
    }
     
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public String save(
            @ModelAttribute("uploadForm") FileUploadForm uploadForm,
                    Model map) {
         
        List<MultipartFile> files = uploadForm.getFiles();
 
        List<String> fileNames = new ArrayList<String>();
         
        if(null != files && files.size() > 0) {
            for (MultipartFile multipartFile : files) {
 
                String fileName = multipartFile.getOriginalFilename();
                fileNames.add(fileName);
                //Handle file content - multipartFile.getInputStream()
 
            }
        }
         
        map.addAttribute("files", fileNames);
        return "file_upload_success";
    }
}

5.编写jsp视图

file_upload_form.jsp

<html>
<head>
    <title>Spring MVC Multiple File Upload</title>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>
$(document).ready(function() {
    //add more file components if Add is clicked
    $('#addFile').click(function() {
        var fileIndex = $('#fileTable tr').children().length - 1;
        $('#fileTable').append(
                '<tr><td>'+
                '   <input type="file" name="files['+ fileIndex +']" />'+
                '</td></tr>');
    });

});
</script>
</head>
<body>
<h1>Spring Multiple File Upload example</h1>

<form method="post" action="save.html"
        **enctype="multipart/form-data"**>

    <p>Select files to upload. Press Add button to add more file inputs.</p>

    <input id="addFile" type="button" value="Add File" />
    <table id="fileTable">
        <tr>
            <td><input name="files[0]" type="file" /></td>
        </tr>
        <tr>
            <td><input name="files[1]" type="file" /></td>
        </tr>
    </table>
    <br/><input type="submit" value="Upload" />
</form>
</body>
</html>

参考:http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-multipart

【讨论】:

  • 感谢您的长时间响应,但文件上传通过 ui 可以正常工作。只是有时,在自动化测试期间,图片上传失败。
  • 不是天生的...但是 +1 的努力。
【解决方案4】:

我以前在两种情况下遇到过这种情况。一次是我的磁盘空间不足,另一次是我在做一些负载测试。

如果您查看How it works 页面,您可以将工具转储到磁盘或将它们保存在内存中。在一种情况下,我在测试期间填满了驱动器,另一种情况下我将项目保存在内存中,但负载超出了我的内存限制。

你是如何设置它的?您用于测试的图像有多大?你在测试期间上传了多少次?有了这些信息,我应该可以提供更多帮助。

【讨论】:

  • 在整个测试套件中,我们总共上传了四张 10kb-1Mb 之间的图像(不超过 1mb)。在服务器上,我们从不将图像写入磁盘,因为图像是在内存中处理的。在测试期间,图像与我们的测试套件打包在一起。
  • 我想我有这个问题。 javadoc 声明默认情况下超过 10K 的任何内容都会写入磁盘。如果您确实想始终处理内存中的项目,您可以在 DiskFileItemFactory 上调用 setSizeThreshold(Integer.MAX_VALUE)。这真的在背后咬了我好几次。试试看,让我知道它是否更适合你。如果没有,我可以到处玩,看看能不能把它复制到我的盒子上。
【解决方案5】:

此代码目前在我的网站上使用,就像一个魅力:

package com.example;

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/api/media")
public class ImageRestService {

    private static final Logger LOG = LoggerFactory.getLogger(ImageRestService.class);

    @RequestMapping(value = "/uploadtemp", method = RequestMethod.POST)
    public String upload(@RequestParam(value = "image") MultipartFile image) {
        try {
            BufferedImage bufferedImage = ImageIO.read(image.getInputStream());
            // process image here
        } catch (IOException e) {
            LOG.error("failed to process image", e);
            return "failure/view/name";
        }
        return "success/view/name";
    }

}

【讨论】:

    【解决方案6】:

    可能项目列表的顺序不固定(取决于时间?)。你的代码

    if (image != null) {
        break;
    }
    

    退出循环而不是尝试下一部分。在您声明的 cmets 中我们遍历文件直到我们可以解析一个,它应该是

    if (image != null) {
        continue;
    }
    

    那么。

    【讨论】:

    • 投反对票的人能解释一下这个答案有什么问题吗?
    猜你喜欢
    • 2011-11-17
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 2015-01-07
    • 1970-01-01
    • 2021-05-17
    • 2016-11-06
    • 2013-11-29
    相关资源
    最近更新 更多