在春季启动中将AWS S3文件作为流下载

时间:2019-11-18 09:48:23

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

我想公开一个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
    }

这里有什么建议,我做错了什么?

2 个答案:

答案 0 :(得分:0)

您可以使用以下示例进行解决

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

答案 1 :(得分:0)

我可以使用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的下载功能,使用常规OutputStream编写内容时,您将得到OutofMemoryError