Pregunta

I use Spring 3.2.5 to process file uploads with a controller. Multipart handling is configured in the 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>

This is the code

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

I was wondering why my Break-point at the first log statement is not reached before the whole file is uploaded? It looks like the request is first read completely before you can start processing.

Is there a way to achieve the following behavior:

  • get file information from the upload as soon, as the upload begins
  • take InputStream and route it through the System to it's target, where it is processed (no reading into RAM or File before)
¿Fue útil?

Solución

Your loop calls request.getParts(), which returns a Collection<Part> and thus require the browser input to be fully parsed before you can even enter the first iteration of your loop. What you call a file upload is really a HTTP request that looks like this:

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
...

To get the list of the parts that make up the request, the framework must first parse the whole request, and it may take a while depending on the file size and network speed.

You may speed things up by parsing the raw InputStream returned by request.getInputStream() by yourself, but currently I don't know any library that lets you process a multipart envelope in a streaming fashion (like, say, the SAX API for XML documents). Also, I'm not entirely sure how this will ever affect the visible performance of the application.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top