【问题标题】:How to directly process Inputstream from fileupload如何直接处理来自文件上传的输入流
【发布时间】:2014-01-07 16:49:19
【问题描述】:

我使用 Spring 3.2.5 通过控制器处理文件上传。 多部分处理配置在web.xml

<servlet>
    <description></description>
    <display-name>rest</display-name>
    <servlet-name>rest</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <multipart-config />
</servlet>

这是代码

@RequestMapping(value = "/{id}", method = RequestMethod.POST)
ResponseEntity<Content> uploadFile(final HttpServletRequest request, @PathVariable final String id)
        throws IOException, ServletException {
    for (final Part part : request.getParts()) {
        log.debug("Content-Type: {}", part.getContentType());
        for (final String key : part.getHeaderNames()) {
            log.debug("Header {}: {}", key, part.getHeader(key));
        }
        log.debug("Name: {}", part.getName());
        log.debug("Size: {}", part.getSize());
        final String fileName = getPartName(part);
        log.debug("File name: {}", fileName);

        final DataSource ds = new DataSource() {
            @Override
            public String getContentType() {
                String ct = ContentController.this.getContentType(part.getContentType(), null);
                if (ct == null) {
                    final Pattern p = Pattern.compile("^.+\\.(.+?)$");
                    final Matcher m = p.matcher(fileName);
                    if (m.matches()) {
                        ct = ContentController.this.getContentType(m.group(1), m.group(1));
                    }
                }
                return ct;
            }

            @Override
            public InputStream getInputStream() throws IOException {
                return part.getInputStream();
            }

            @Override
            public String getName() {
                return fileName;
            }

            @Override
            public OutputStream getOutputStream() throws IOException {
                return null;
            }
        };

        final Content content = service.storeFile(ds, id, part.getSize());
        if (content != null) {
            return new ResponseEntity<>(content, IE89PostWorkaround(request), HttpStatus.CREATED);
        }
    }
    return new ResponseEntity<>(new Content(), IE89PostWorkaround(request), HttpStatus.BAD_REQUEST);
}

我想知道为什么在整个文件上传之前没有达到第一个日志语句的断点? 看起来请求在您开始处理之前首先被完全读取。

有没有办法实现以下行为:

  • 在上传开始后立即从上传中获取文件信息
  • 获取InputStream 并通过系统将其路由到它的目标,在那里进行处理(之前没有读入 RAM 或文件)

【问题讨论】:

    标签: java jakarta-ee file-upload servlet-3.0


    【解决方案1】:

    您的循环调用request.getParts(),它返回一个Collection&lt;Part&gt;,因此在您进入循环的第一次迭代之前需要完全解析浏览器输入。您所说的文件上传实际上是一个如下所示的 HTTP 请求:

    GET /fileUpload.do
    Content-Type: multipart/form-data; boundary=--limit
    
    --limit
    content-disposition: form-data; name="description"
    content-type: text/plain
    
    This is the description of the file
    
    --limit
    content-disposition: form-data; name="image"
    content-type: image/png
    
    lksdf82203j1897239481231kadlqcdladaod82y3o98dqjdhdqkdh
    q9wrcfdhlqhfoqwfn92q38uycrnwehrnqolwhfrnoq83y018yn8cy2
    oqwdfopiqweuroq338rquncqwurqwercqfjqwcngreydisajf238jd
    ...
    

    要获取组成请求的部分列表,框架必须首先解析整个请求,根据文件大小和网络速度,可能需要一段时间。

    您可以通过自己解析request.getInputStream() 返回的原始InputStream 来加快速度,但目前我不知道有任何库可以让您以流方式处理多部分信封(例如,SAX XML 文档的 API)。另外,我不完全确定这将如何影响应用程序的可见性能。

    【讨论】:

    • 我真的很想知道 Java 中没有事件驱动的文件上传处理。我们目前有 Servlet 版本 3.1。从来没有人要求过吗?对我来说,这似乎是处理非常大的文件或避免对文件进行 DOS 攻击的唯一方法(因为在您拒绝文件之前,它完全由 servlet 框架处理)......
    • 其实也不是很震撼。您可以设置请求大小的限制,这是一种不常见的情况,事件 API 会导致更好的性能。此外,DOS 攻击与文件“上传”关系不大
    猜你喜欢
    • 1970-01-01
    • 2014-10-01
    • 2019-09-12
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多