S3버킷은 팀원분이 만들어주셔서 여기선 등록 이후의 부분만 다루겠습니다.
S3에 이미지를 저장하고 fileUrl을 리턴받아 데이터베이스에 저장하는 구조입니다.
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
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
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 서비스와 상호작용할 수 있게 해주는 역할을 합니다.
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() 메서드를 통해 필요없는 앞부분을 잘라야 정상적으로 삭제가 됩니다.
클라이언트에서 이미지를 받아갈때 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오류를 피할 수 있습니다. "*" 부분은 필요한대로 수정하시면 됩니다.