본문 바로가기
Skills/Spring

Spring boot 3.0 + S3 서비스 적용 By Spring Cloud for AWS

by Hoseok 2023. 6. 6.
728x90
반응형

Spring Cloud AWS

 

 

Spring Cloud for AWS 공식문서

https://spring.io/projects/spring-cloud-aws

 

Spring Cloud for Amazon Web Services

Spring Cloud for Amazon Web Services is a community-run project. The website is https://awspring.io/ and the source repository is located at https://github.com/awspring/spring-cloud-aws. Spring Cloud for Amazon Web Services, eases the integration with host

spring.io

 

공식문서에 들어가면, 아래의 문구가 나와있다.

Spring Cloud for Amazon Web Services is a community-run project.

 

즉, 커뮤니티에서 운영하는 프로젝트라는 것.

 

아래는 공식 사이트이다.

 

https://awspring.io/

 

Spring Cloud AWS

Brings the power of AWS to Spring Boot applications in Spring idiomatic way

awspring.io

 

AWS는 자체적으로 Java SDK를 제공하지만, Spring Cloud AWS는 스프링 기반 모듈을 통합하여 AWS 서비스를 제공한다는 장점이 있기 때문에 Spring Cloud AWS를 사용할 것이다.

 

 

현재 최신 버전은 3.0.0이고 GA(General Availability), 테스트가 완료된 정식 릴리즈 버전을 의미한다.

 

SNAPSHOT은 특정 시점의 버전으로, 이후에 기능이 추가되거나 삭제될 수 있기 때문에 GA가 붙은 버전을 사용하자.

 

또한 3.0.0 이상은 스프링 부트 3.0과 적합하므로

 

스프링 부트 3.0 이상을 사용하고 있다면 Spring Cloud AWS 3.0.0 이상 버전을 사용하도록 하자.

 

*gradle 의존성 추가

implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.0.0'

 

스타터는 스프링 애플리케이션에서 모듈을 사용하는 데 필요한 종속성이 기본적으로 포함되어 있다.

 

spring-cloud-aws-starter-s3 역시 AWS 관련 기능을 사용하기 위한 모든 종속성들이 자동으로 추가되게 만들어져 있다.

 

 

파일 업로드 방식

 

파일을 업로드 하는 방식은 크게 Multipart File, Base64 방식이 존재한다.

 

Multipart File은 파일을 업로드할 때, 파일을 여러 부분으로 분할하여 전송하는 방식이고,

 

Base64는 파일을 8비트 이상의 바이너리 데이터를 ASCII 문자로 변환하여 텍스트 데이터로 전송하는 방식이다.

 

결론적으로는 Multipart File 방식을 사용하게 되었는데,

 

그 이유는 Base64 같은 경우,

 

첫 번째로, 인코딩을 하게 될 시, 원래 바이너리 데이터보다 크기가 33% 정도 증가한다.

 

고화질 사진을 업로드할 때, 데이터 크기가 커지게 되므로 적합한 방식은 아니라고 생각했다.

 

두 번째로, 인코딩과 디코딩 작업이 추가적으로 발생한다는 단점이 존재한다.

 

그에 반해,

 

Multipart File은 대용량 파일 전송을 작은 부분으로 나누어 전송이 가능하고, 이어받기가 가능하며,

 

여러 부분을 동시에 전송함으로써 전체 파일 전송 시간을 단축시킬 수 있다는 장점이 있기 때문에

 

Multipart File 방식을 사용할 것이다.

 

 


코드

 

 

Spring Cloud AWS S3는 AWS에서 제공하는 JAVA for SDK 와는 달리, Config 파일을 따로 만들지 않아도 된다.

 

CredentialsProviderAutoConfiguration라는 클래스가,

 

application.yml에 등록된 access key와 secret key를 찾아서

 

Credential과 관련된 Provider 객체들을 생성하고, AWS 서비스에 접근이 가능해지기 때문이다.

 

물론 내부적으로는 software.amazon.awssdk.services.s3 라이브러리를 사용해서 구현하고 있다.

 

 

application.yml

  spring:
      cloud:
        aws:
          credentials:
            access-key: ${AWS_ACCESS_KEY}
            secret-key: ${AWS_SECRET_KEY}
          s3:
            bucket: ${AWS_S3_BUCKET}
          region:
            static: ${AWS_S3_REGION}

 

 

S3Service

import io.awspring.cloud.s3.ObjectMetadata;
import io.awspring.cloud.s3.S3Operations;
import io.awspring.cloud.s3.S3Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

@Service
public class S3Service {
    private static final String BUCKET = System.getenv("AWS_S3_BUCKET");
    private final S3Operations s3Operations;

    public S3Service(S3Operations s3Operations) {
        this.s3Operations = s3Operations;
    }

    @Transactional
    public ResponseEntity<?> upload(MultipartFile multipartFile, String key) throws IOException {
        if (!MediaType.IMAGE_PNG.toString().equals(multipartFile.getContentType()) &&
                !MediaType.IMAGE_JPEG.toString().equals(multipartFile.getContentType())) {
            return ResponseEntity.badRequest().body("사진 파일만 업로드 가능합니다");
        }

        try (InputStream is = multipartFile.getInputStream()) {
            s3Operations.upload(BUCKET, key, is,
                    ObjectMetadata.builder().contentType(multipartFile.getContentType()).build());
        }

        return ResponseEntity.accepted().build();
    }

    @Transactional
    public ResponseEntity<?> download(@RequestParam String key) {
        S3Resource s3Resource = s3Operations.download(BUCKET, key);

        if (MediaType.IMAGE_PNG.toString().equals(s3Resource.contentType())) {
            return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG).body(s3Resource);
        }

        if (MediaType.IMAGE_JPEG.toString().equals(s3Resource.contentType())) {
            return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(s3Resource);
        }

        return ResponseEntity.badRequest().body("사진 파일만 다운로드 가능합니다");
    }
}

 

S3Operations 인터페이스는 S3Client보다 더 높은 레벨의 추상화된 인터페이스로, 

 

버킷을 생성, 삭제하거나, 객체를 업로드, 다운로드하는 기능들을 가지고 있다.

 

S3Template이라는 클래스가 S3Operations를 구현하고 있으며,

 

software.amazon.awssdk.services.s3의 S3Client, S3Presigner 객체,

 

 io.awspring.cloud.s3의 S3OutputStreamProvider, S3ObjectConverter 객체를

 

생성자 매개변수로 받아서 만들어지고 있다.

 

결국 내부적으로는 AWS JAVA for SDK를 이용하여 만들어졌다는 것을 알 수 있다.

 

 

728x90
반응형