스프링 - Object Storage(S3) 사용 시 로컬에 파일 저장하지 않고 전송하기

박진형·2021년 9월 2일
1

Spring

목록 보기
4/9

문제

네이버 클라우드 플랫폼의 Object Storage에서 제공하는 예제에는 클라이언트로부터 전송된 파일을 Object Storage에 전송하려면 전송된 MultipartFile을 File 형식으로 바꿔야하고, 그러려면 로컬에 저장하는 방식을 사용해야된다.
전송된 파일을 로컬에 저장하는것도 찜찜하고, 쓰기 작업을하니까 성능상 좋지도 않을 것 같았다.

네이버 클라우드 플랫폼 제공 예제

ref - https://guide.ncloud-docs.com/docs/storage-storage-8-1

final String endPoint = "https://kr.object.ncloudstorage.com";
final String regionName = "kr-standard";
final String accessKey = "ACCESS_KEY";
final String secretKey = "SECRET_KEY";

// S3 client
final AmazonS3 s3 = AmazonS3ClientBuilder.standard()
    .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, regionName))
    .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
    .build();

String bucketName = "sample-bucket";
String objectName = "sample-large-object";

File file = new File("/tmp/sample.file");
long contentLength = file.length();
long partSize = 10 * 1024 * 1024;

try {
    // initialize and get upload ID
    InitiateMultipartUploadResult initiateMultipartUploadResult = s3.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucketName, objectName));
    String uploadId = initiateMultipartUploadResult.getUploadId();

    // upload parts
    List<PartETag> partETagList = new ArrayList<PartETag>();

    long fileOffset = 0;
    for (int i = 1; fileOffset < contentLength; i++) {
        partSize = Math.min(partSize, (contentLength - fileOffset));

        UploadPartRequest uploadPartRequest = new UploadPartRequest()
            .withBucketName(bucketName)
            .withKey(objectName)
            .withUploadId(uploadId)
            .withPartNumber(i)
            .withFile(file)
            .withFileOffset(fileOffset)
            .withPartSize(partSize);

        UploadPartResult uploadPartResult = s3.uploadPart(uploadPartRequest);
        partETagList.add(uploadPartResult.getPartETag());

        fileOffset += partSize;
    }

    // abort
    // s3.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, objectName, uploadId));

    // complete
    CompleteMultipartUploadResult completeMultipartUploadResult = s3.completeMultipartUpload(new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETagList));
} catch (AmazonS3Exception e) {
    e.printStackTrace();
} catch(SdkClientException e) {
    e.printStackTrace();
}

해결

uploadPartRequest 에서 제공하는 함수를 잘 살펴본다.

inputStream을 설정할 수 있다.

그러면 MultipartFile 에서 제공하는 함수를 잘 살펴본다.

inputStream을 받아올 수 있다.

그러면

  UploadPartRequest uploadPartRequest = new UploadPartRequest()
            .withBucketName(bucketName)
            .withKey(objectName)
            .withUploadId(uploadId)
            .withPartNumber(i)
            .withFile(file)
            .withFileOffset(fileOffset)
            .withPartSize(partSize);

여기에서 아래와 같이 withFile 말고 withInputStream을 사용하면된다.

UploadPartRequest uploadPartRequest = new UploadPartRequest()
                        .withBucketName(bucketName)
                        .withKey(objectName)
                        .withUploadId(uploadId)
                        .withPartNumber(i)
                        .withInputStream(multipartFile.getInputStream())
                        .withFileOffset(fileOffset)
                        .withObjectMetadata(objectMetadata)
                        .withPartSize(partSize);

0개의 댓글