Spring boot -> Aws S3 이미지 파일 업로드

한꼬북·2022년 10월 10일
0

정리

목록 보기
2/2
post-thumbnail

Spring boot -> aws s3 업로드

  • 아래 이미지와 같은 단계로 이미지를 업로드 함

1. Connection

@Configuration
public class AwsConfig {

    @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 amazonS3() {
        AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
        return AmazonS3ClientBuilder.standard()
            .withRegion(region)
            .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
            .build();
    }
}
  • AWS S3에 Connection을 하고 S3Client를 생성하는 과정
  • AccessKey와 SecretKey는 각별히 주의해야 한다. 잘못해서 Github에 올리다간 과금 폭탄을 맞을 수 있음.
  • Region은 사용되는 지역으로 아시아의 서울 Region을 사용함
AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
  • AWS에 우리가 생성한 S3에 접근할 수 있는 AccessKey와 SecretKey의 정보가 담겨있는 객체로 AWSCredentials는 인터페이스 구현체로는 BasicAWSCredentials을 사용한다.
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
  • 위에 만들어 놓은 S3에 접근할 수 있는 자격 증명이 담겨있는 awsCredentials를 AWSStaticCredentialsProvider 생성자에 담아주는데 AWSStaticCredentialsProvider는 private final 필드로 AWSCredentials를 가지고 있다.

2. 파일 업로드

@RequiredArgsConstructor
@Component
public class S3FileUtil {

    private final AmazonS3 amazonS3;

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

    public String upload(MultipartFile file) throws IOException {

        String fileName = UUID.randomUUID() + file.getOriginalFilename();
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(file.getInputStream().available());
        amazonS3.putObject(bucket, fileName, file.getInputStream(), objectMetadata);
        
		return amazonS3.getUrl(bucket, fileName).toString();
    }

}
  • bucket은 s3에서 사용하는 bucket의 이름이고 파일을 업로드할 때 겹치지 않기 위해 UUID를 추가로 파일 이름에 붙여서 업로드하도록 했음
private final AmazonS3 amazonS3;
  • 1번에서 connection한 AwsS3Client 사용하기 위한 주입
 ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(file.getInputStream().available());
  • ObjectMetadata는 업로드할 객체에 대한 설정 값을 넣어줄 수 있음 우리는 간단하게 업로드 할 파일이 몇 byte인지 알려주도록 했다. 이 설정을 안하면 out of memory error가 발생할 수 있음! 참고로 Content-type을 설정해주지 않을 경우 application/octet-stream 으로 설정된다. 더 자세한 것은 -> AwsDocs
amazonS3.putObject(bucket, fileName, file.getInputStream(), objectMetadata);
  • s3에 파일을 업로드 하는 부분, file.getInputStream() 부분에서 IOException 예외가 발생할 수 있으니 서비스 로직에서 catch해서 따로 처리하면 될 듯하다.

3. 업로드된 파일 Url 가져오기

return amazonS3.getUrl(bucket, fileName).toString();
  • bucket과 UUID 및 날짜 값을 추가했던 fileName을 넣어주면 URL 자체를 반환하는데 AmazonS3를 상속받은 AmazonS3Client가 구현한 getUrl(); 메서드를 통해 가져오게 된다.
  • 이때 AWS S3에서 설정한 객체들에 대한 접근 설정에 따라 접근이 불가능 할 수도 있음

추가

1. Yml 파일 설정 및 dependencies

cloud:
  aws:
    bucket: 
    credentials:
      access-key: 
      secret-key: 
    region:
      static: ap-northeast-2
    stack:
      auto: false
  • stack.auto: 설정 부분은 프로젝트 실행 시 CloudFormation을 생성하는데 우리는 이것을 사용하지 않을 것이므로 false로 지정해야 함 만약 false로 지정해주지 않을 경우 아래와 같은 예외가 발생한다.
Caused by: java.lang.IllegalArgumentException: No valid instance id defined
    at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.9.jar:5.3.9]
    at org.springframework.cloud.aws.core.env.stack.config.AutoDetectingStackNameProvider.autoDetectStackName(AutoDetectingStackNameProvider.java:85) ~[spring-cloud-aws-core-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.cloud.aws.core.env.stack.config.AutoDetectingStackNameProvider.afterPropertiesSet(AutoDetectingStackNameProvider.java:70) ~[spring-cloud-aws-core-2.2.6.RELEASE.jar:2.2.6.RELEASE]
  • dependencies
implementation "com.amazonaws:aws-java-sdk-s3:1.12.281"

2. Aws S3 bucket 정책 설정

{
	"Version": "2012-10-17",
	"Id": "Policy1665469475203",
	"Statement": [
		{
			"Sid": "Stmt1665469468407",
			"Effect": "Allow",
			"Principal": "*",
			"Action": [
				"s3:DeleteObject",
				"s3:GetObject",
				"s3:PutObject"
			],
			"Resource": "arn:aws:s3:::버킷이름/*"
		}
	]
}
  • 버킷 정책을 위처럼 퍼블릭으로 열어야만 누구나 객체에 접근이 가능하다.
"Principal": "*"
  • 접근 권한을 설정
"Action": [
	"s3:DeleteObject",
	"s3:GetObject",
	"s3:PutObject"
],
  • s3 버킷에 대한 퍼블릭으로 열린 액션을 지정
"Resource": "arn:aws:s3:::버킷이름/*"
  • 특정 버킷에 있는 모든 객체에 접근할 수 있도록 설정
  • 참고로 S3버킷 정책 편집에서 정책생성기를 이용해 간편하게 생성할 수 있다.
profile
오히려 좋아, 자 가보자고!

0개의 댓글