如何在 Spring MVC 中为大文件创建八位字节流端点?

问题描述 投票:0回答:1

请帮助我找到使用 Spring MVC 实现下载大文件的端点的正确方法。

我知道涉及显式写入

HttpServletResponse
输出流的方法:

@PostMapping("/download")
void downloadFile(
     @PathVariable("path") String path,
     HttpServletResponse response
) throws Exception {
    try (var output = response.getOutputStream()) {
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        service.readFilePart(path, output));
    }
}

但是,一个缺点是,当

service.readFilePart
方法引发异常时,端点仍然返回 HTTP 200,而不是带有错误状态和一些 JSON 的响应。

我找到了几种方法,但它们都建议在发送响应之前收集内存中的所有文件数据,例如:

try (var output = new ByteArrayOutputStream()) {
    service.readFilePart(path, output));
    return ResponseEntity.ok()
                  .contentType(MediaType.APPLICATION_OCTET_STREAM)
                  .body(output.toByteArray());
}

我正在寻找一种解决方案,可以处理大文件,而无需将大于 1MB 的块加载到内存中,同时还可以利用标准 Spring MVC 功能(例如异常处理程序)。

似乎使用

HttpServletResponse
参数可能会破坏抽象级别。是否有可能在Spring MVC中使用更高级别的抽象来实现类似的功能?

java spring-mvc octet-stream
1个回答
0
投票

@GetMapping("/download")
public ResponseEntity<StreamingResponseBody> downloadFile(@RequestParam("path") String path) {
    try {
        // Assuming you have a method to get the file size
        long fileSize = fileService.getFileSize(path);

        StreamingResponseBody stream = outputStream -> {
            try {
                fileService.readFilePart(path, outputStream);
            } catch (IOException e) {
                throw new RuntimeException("Failed to write file", e);
            }
        };

        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + extractFilename(path) + "\"")
                .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileSize))  // Set the content length
                .body(stream);

    } catch (Exception e) {
        // Log the exception and return an appropriate error response
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(null);  // You can customize the response as needed
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.