【问题标题】:Downloading AWS S3 file as a stream in Spring boot在 Spring Boot 中将 AWS S3 文件作为流下载
【发布时间】:2021-11-25 14:42:40
【问题描述】:

我想公开一个 API 以将 S3 存储桶文件内容作为流下载给它的消费者。 API URL 类似于 /downloadfile/**,即 GET 请求。

  1. 我现在尝试使用 accept header= 的返回类型应该是什么 应用程序/八位字节流不起作用。
  2. 我不想将文件的内容写入任何文件并发送。它应该以流的形式返回。

这是我到目前为止编写的控制器伪代码,它一直给我 406 错误。

 @GetMapping(value = "/downloadfile/**", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
    public ResponseEntity<Object> downloadFile(HttpServletRequest request) {
       //reads the content from S3 bucket and returns a S3ObjectInputStream
       S3ObjectInputStream object = null;
       object = publishAmazonS3.getObject("12345bucket", "/logs/file1.log").getObjectContent();
       return object
    }

关于这样做的方式以及我做错了什么,这里有什么建议吗?

【问题讨论】:

    标签: java spring-boot amazon-s3 java-8


    【解决方案1】:

    我能够使用 Spring 中的 StreamingResponseBody 类将文件作为流下载。

    这是我使用的代码:

        @GetMapping(value = "/downloadfile/**", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
        public ResponseEntity<S3ObjectInputStream> downloadFile(HttpServletRequest request) {
           //reads the content from S3 bucket and returns a S3ObjectInputStream
           S3Object object = publishAmazonS3.getObject("12345bucket", "/logs/file1.log");
           S3ObjectInputStream finalObject = object.getObjectContent();
    
            final StreamingResponseBody body = outputStream -> {
                int numberOfBytesToWrite = 0;
                byte[] data = new byte[1024];
                while ((numberOfBytesToWrite = finalObject.read(data, 0, data.length)) != -1) {
                    System.out.println("Writing some bytes..");
                    outputStream.write(data, 0, numberOfBytesToWrite);
                }
                finalObject.close();
            };
            return new ResponseEntity<>(body, HttpStatus.OK);
        }
    

    测试流媒体是否正确完成的方法是下载一个大约 400mb 的文件。通过传入 vm 选项将 Xmx 减少到 256mb。现在比较一下使用StreamingResponseBody和不使用StreamingResponseBody的下载功能,当使用常规的OutputStreams写入内容时,你会得到OutofMemoryError

    【讨论】:

    • 当我尝试这个时,我得到这个:错误:不兼容的类型:无法推断 ResponseEntity 的类型参数 return new ResponseEntity(streamingResponseBody, HttpStatus.OK); ^ 原因:推理变量 T 具有不兼容的边界等式约束:InputStream 下限:StreamingResponseBody
    【解决方案2】:

    你可以用下面的例子解决

    import java.io.ByteArrayOutputStream;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import com.grokonez.s3.services.S3Services;
    
    @RestController
    public class DownloadFileController {
    
        @Autowired
        S3Services s3Services;
    
        /*
         * Download Files
         */
        @GetMapping("/api/file/{keyname}")
        public ResponseEntity<byte[]> downloadFile(@PathVariable String keyname) {
            ByteArrayOutputStream downloadInputStream = s3Services.downloadFile(keyname);
    
            return ResponseEntity.ok().contentType(contentType(keyname))
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + keyname + "\"")
                    .body(downloadInputStream.toByteArray());
        }
    
        private MediaType contentType(String keyname) {
            String[] arr = keyname.split("\\.");
            String type = arr[arr.length - 1];
            switch (type) {
            case "txt":
                return MediaType.TEXT_PLAIN;
            case "png":
                return MediaType.IMAGE_PNG;
            case "jpg":
                return MediaType.IMAGE_JPEG;
            default:
                return MediaType.APPLICATION_OCTET_STREAM;
            }
        }
    }
    

    【讨论】:

    • 老兄,代码先在这里下载文件到内存.body(downloadInputStream.toByteArray());
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 2019-02-16
    • 1970-01-01
    • 2020-06-12
    相关资源
    最近更新 更多