user3971703
user3971703

Reputation:

spring rest: uploading large files (1GB) via rest controller

[context: java 8, spring boot 1.5.1]

We are creating a RESTful service where we need to be able to upload large files. What I want is an api that would look something like this

@RequestLine("POST /object")
@Headers("Content-Type: multipart/form-data")
void create(InputStreamResource resource, ...);

I don't want to use a MultipartFile as the entire file would be read, nor an HttpServletRequest as that doesn't seem to belong here but rather begs the need for a HttpMessageConverter of sorts. Having said that, with an HttpServletRequest I could solve the problem as follows

ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iterator = upload.getItemIterator(request);
while (iterator.hasNext()) {
  FileItemStream e = iterator.next();
  if (!e.isFormField()) {
    InputStream inputStream = item.openStream();
    //...
  }
}

Ideally I would like an InputStream or something that wraps one, e.g. InputStreamResource(as shown above).

Any suggestions would be appreciated.

Upvotes: 4

Views: 11885

Answers (1)

Igor Bljahhin
Igor Bljahhin

Reputation: 987

I got it working in this way and it seems the only way to handle upload without temp file or reading the file into byte array using @RequestBody annotation, as was suggested on stackoverflow.com in one thread:

@RequestMapping("firmware/{firmwareId:\\d+}/logs/upload")
public
@ResponseBody
ResponseEntity handleUploadLogs(@PathVariable("firmwareId") final Long firmwareId, final HttpServletRequest request) {
    try (final InputStream is = getInputStream(request)) {
        if (is != null) {
            firmwareContentService.uploadLogs(firmwareId, is);

            return ok().build();
        } else {
            return badRequest().build();
        }
    } catch (IOException | FileUploadException e) {
        return badRequest().build();
    }
}

private InputStream getInputStream(final HttpServletRequest request) throws IOException, FileUploadException {
    final ServletFileUpload upload = new ServletFileUpload();
    final FileItemIterator iterator = upload.getItemIterator(request);

    InputStream is = null;

    while (iterator.hasNext()) {
        final FileItemStream item = iterator.next();

        if (!item.isFormField()) {
            is = item.openStream();

            break;
        }
    }

    return is;
}

UPDATE

This simple code worked for me as well. Just put InputStream into method parameters:

@PostMapping("firmware/{firmwareId:\\d+}/logs/upload")
public
@ResponseBody
ResponseEntity handleUploadLogs(@PathVariable("firmwareId") final Long firmwareId, final InputStream is) {
    try {
        firmwareContentService.uploadLogs(firmwareId, is);

        return ok().build();
    } catch (IOException e) {
        return badRequest().build();
    }
}

The "simple code" above is not actually working. InputStream in method parameter contains whole http request.

Upvotes: 1

Related Questions