[공부정리] AWS S3를 이용한 파일 저장

jeyong·2024년 2월 3일
0

공부 / 생각 정리  

목록 보기
22/120
post-custom-banner


이번 게시글에서는 AWS S3를 이용하여 새 파일을 저장하는 과정을 기술하겠다. 본래에는 도커를 이용하여 파일을 관리할 생각이었으나, S3를 사용하면 얻는 장점이 많기도 하고 CloudFront를 적용하여 Cash에 대한 장점도 얻을 수 있어서 S3를 적용하기로 하였다. 이로인해 아래 적용한 내용들은 dev 환경에서 S3를 이용하도록 구성되어 있다.

1. AWS S3 설정

1-1. S3(Simple,Storage, Service)

S3는 AWS(Amazon Web Service)에서 제공하는 인터넷 스토리지 서비스이다.

  • 내구도를 자랑하며 정보를 안전하게 저장 할 수 있다.
  • 저렴한 비용으로 사용이 가능하다.
  • 보안성이 뛰어나다.
  • 속도가 빠르다.

AWS S3 설정과 관련한 부분은 다른 게시글에 잘 정리되어있으므로 해당 게시글에서는 정리하지 않고 간단하게 게시글을 추천해주고 넘어가겠다.

[AWS] S3 생성 및 Spring Boot 연동

2. Spring Boot 설정

Spring Boot에서 S3와의 연동을 위해 build.gradle과 application-dev.yml, S3 관련 설정 클래스를 구성한다.

build.gradle

implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' //AWS S3

AWS S3와 연동하기 위한 의존성을 추가한다.

application-dev.yml

cloud:
  aws:
    region:
      static: ${s3.region}
    s3:
      bucket: ${s3.bucket}
    stack:
      auto: false
    credentials:
      access-key: ${s3.access-key}
      secret-key: ${s3.secret-key}

AWS 리전, S3 버킷 이름, 액세스 키, 시크릿 키등 을 설정한다.

S3Config

@Profile("dev")
@Configuration
public class S3Config {
    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Bean
    public AmazonS3 s3Builder() {
        AWSCredentials basicAWSCredentials = new BasicAWSCredentials(accessKey, secretKey);

        return AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(basicAWSCredentials))
                .withRegion(region).build();
    }
}

S3Config 클래스는 AWS S3 서비스를 위한 Spring 설정을 제공한다.

  • @Profile("dev") 어노테이션을 사용해 개발 환경에서만 적용된다.
  • Builder 메서드는 AWS 자격 증명과 리전을 설정해 AmazonS3 클라이언트 객체를 생성하고 반환한다.

S3FileService

@Profile("dev")
@Service
@RequiredArgsConstructor
public class S3FileService implements FileService {

    private final AmazonS3 amazonS3Client;

    @Value("${cloud.aws.s3.bucket}")
    private String bucketName;

    @Override
    public void upload(MultipartFile file, String filename) {
        try {
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentType(file.getContentType());
            objectMetadata.setContentLength(file.getSize());

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, filename, file.getInputStream(), objectMetadata);

            amazonS3Client.putObject(putObjectRequest);
        } catch(Exception e) {
            throw new FileUploadFailureException(e);
        }
    }

    @Override
    public void delete(String filename) {
        try {
            amazonS3Client.deleteObject(bucketName, filename);
        } catch (Exception e) {
            throw new FileDeleteFailureException(e);
        }
    }
}

S3FileService 클래스는 파일 업로드와 삭제 기능을 구현한다.

  • @Service 어노테이션으로 서비스 레이어임을 명시한다.
  • AWS S3 클라이언트를 주입받아 upload 메서드에서는 파일 메타데이터 설정 후 S3 버킷에 파일을 업로드한다. delete 메서드로 S3 버킷에서 파일을 삭제한다.

S3FileServiceTest.java

@ExtendWith(MockitoExtension.class)
class S3FileServiceTest {
    @InjectMocks
    private S3FileService s3FileService;
    @Mock
    private AmazonS3 amazonS3Client;

    @BeforeEach
    void beforeEach() {
        ReflectionTestUtils.setField(s3FileService, "bucketName", "my-bucket");
    }

    @Test
    void uploadTest() throws Exception {
        // given
        MultipartFile file = new MockMultipartFile("file", "test.txt", "text/plain", "test content".getBytes());
        String filename = "testFile.txt";

        // when
        s3FileService.upload(file, filename);

        // then
        verify(amazonS3Client).putObject(any(PutObjectRequest.class));
    }

    @Test
    void uploadExceptionByFileUploadFailureException() {
        // given
        MultipartFile file = new MockMultipartFile("file", "test.txt", "text/plain", new byte[0]);

        // then
        doThrow(new RuntimeException("S3 Upload Failed")).when(amazonS3Client).putObject(any(PutObjectRequest.class));

        // when
        assertThrows(FileUploadFailureException.class, () -> {
            s3FileService.upload(file, "test.txt");
        });
    }

    @Test
    void deleteTest() {
        // given
        String filename = "testFile.txt";

        // when
        s3FileService.delete(filename);

        // then
        verify(amazonS3Client).deleteObject(any(String.class), eq(filename));
    }

    @Test
    void deleteExceptionByFileDeleteFailureException() {
        // given
        String filename = "nonExistentFile.txt";

        // then
        doThrow(new RuntimeException("S3 Delete Failed")).when(amazonS3Client).deleteObject(any(DeleteObjectRequest.class));

        // when
        assertThrows(FileDeleteFailureException.class, () -> {
            s3FileService.delete(filename);
        });
    }
}

S3FileServiceTest 클래스는 S3FileService의 기능을 테스트한다.

  • Mockito를 사용해 AmazonS3 클라이언트의 모의 객체를 S3FileService에 주입한다.
  • uploadTest에서는 파일 업로드를 시뮬레이션하고 putObject 호출을 검증한다.
  • deleteTest에서는 파일 삭제 기능을 검증한다.

3. 실행 결과

S3 버킷에 파일이 잘 업로드된 모습을 확인할 수 있다.

4. 마무리

AWS S3를 활용한 파일 저장은 간단하며 효율적이다. 이 과정을 통해 파일을 안전하고 빠르게 관리할 수 있다.
추가로, Spring Boot에서 S3를 활용하는 방법을 잘 설명한 Spring Boot에서 S3에 파일을 업로드하는 세 가지 방법을 추천하며 마무리 하겠다.

profile
노를 젓다 보면 언젠가는 물이 들어오겠지.
post-custom-banner

0개의 댓글