AWS S3를 이용한 이미지 등록

김영식·2023년 7월 28일

S3버킷은 팀원분이 만들어주셔서 여기선 등록 이후의 부분만 다루겠습니다.
S3에 이미지를 저장하고 fileUrl을 리턴받아 데이터베이스에 저장하는 구조입니다.

build.gradle에 의존성 추가

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

application.yml에 설정 추가

cloud:
  aws:
    s3:
      bucket: my-github-actions-s3-burket
    credentials:
      access-key: ${AWS_ACCESS_KEY}
      secret-key: ${AWS_SECRET_KEY}
    region:
      static: ap-northeast-2
      auto: false
    stack:
      auto: false

S3config 클래스 작성

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@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 AmazonS3Client amazonS3Client() {
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);

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

AmazonS3Client 객체를 생성하여 Spring 컨텍스트에 빈으로 등록하고, 해당 빈은 어플리케이션에서 필요한 곳에서 주입되어 Amazon S3 서비스와 상호작용할 수 있게 해주는 역할을 합니다.

S3Uploader 작성

import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.ObjectMetadata;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


import java.io.IOException;
import java.util.UUID;

@Slf4j
@RequiredArgsConstructor
@Service
public class S3Uploader {

    private final AmazonS3Client amazonS3Client;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;
    private final AmazonS3 amazonS3;
    @Value("${cloud.aws.region.static}")
    private String region;


    public String upload(MultipartFile multipartFile) {
        String s3FileName = UUID.randomUUID()+"";

        ObjectMetadata objMeta = new ObjectMetadata();
        objMeta.setContentLength(multipartFile.getSize());

        try {
            amazonS3.putObject(bucket, s3FileName, multipartFile.getInputStream(), objMeta);
        } catch (IOException e) {
            log.error("Failed to upload file to S3", e);
            // 예외 처리: IOException 발생 시 로그 출력
        }

        return amazonS3.getUrl(bucket, s3FileName).toString();
    }

    public void delete(String fileUrl) {
        try {
            String fileKey = fileUrl.substring(68);
            amazonS3.deleteObject(bucket, fileKey);
        } catch (SdkClientException e) {
            log.error("Failed to delete file", e);
        }
    }
}

이미지파일을 S3 버킷에 등록하거나 삭제하는 클래스입니다.
업로드 시 파일 이름은 UUID.randomUUID() 메서드를 통해
랜덤한 숫자와 문자로 구성됩니다. ex)xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

이미지 삭제는 amazonS3.deleteObject()에 버킷주소와 파일의 키값을 넣어주면 됩니다.
주의할점은 데이터베이스에 저장된 fileUrl은 https://{버킷주소}/{키값} 이런식으로 저장이 되어서
substring() 메서드를 통해 필요없는 앞부분을 잘라야 정상적으로 삭제가 됩니다.

CORS 설정

클라이언트에서 이미지를 받아갈때 S3 버킷에 직접적으로 요청을 한다면 CORS오류를 만나게 됩니다.
그럴경우 버킷 -> 권한 탭 -> CORS 에 가서

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "x-amz-server-side-encryption",
            "x-amz-request-id",
            "x-amz-id-2"
        ],
        "MaxAgeSeconds": 3000
    }
]

이렇게 설정해주신다면 CORS오류를 피할 수 있습니다. "*" 부분은 필요한대로 수정하시면 됩니다.

0개의 댓글