dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
}
의존성을 추가한다.
# S3
cloud.aws.region.static= ap-northeast-2
cloud.aws.s3.bucket= testy-pie
cloud.aws.stack.auto=false
cloud.aws.credentials.accessKey= 여기 엑세스키
cloud.aws.credentials.secretKey= 여기 시크릿키
S3관련된 설정을 추가해준다. 같은 곳에 기재해도 되고 .properties 나 .yml을 2개 만들어서 accessKey와 secretKey를 분리해도 된다.
이처럼 2개로 분리하여 키값들을 따로 관리할 경우, 키 값들이 들어있는 .properties를 사용할 수 있도록 application.properties 에 아래의 코드를 추가해줘야한다.
spring.profiles.active=s3
@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.access-key}")
private String iamAccessKey;
@Value("${cloud.aws.credentials.secret-key}")
private String iamSecretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(iamAccessKey, iamSecretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region).enablePathStyleAccess()
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
S3를 사용하기 위한 Config 클래스를 작성해준다.
@Slf4j
@RequiredArgsConstructor
@Component
public class S3Uploader {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
public String upload(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile).orElseThrow(
() -> new IllegalArgumentException("MultipartFile -> File로 전환이 실패했습니다."));
return upload(uploadFile, dirName);
}
private String upload(File uploadFile, String dirName) {
String fileName = dirName + "/" + uploadFile.getName();
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile);
return uploadImageUrl;
}
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, uploadFile).withCannedAcl(
CannedAccessControlList.PublicRead));
return amazonS3Client.getUrl(bucket, fileName).toString();
}
private void removeNewFile(File targetFile) {
if (targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
} else {
log.warn("파일이 삭제되지 못했습니다.");
}
}
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(file.getOriginalFilename());
System.out.println("convertFile = " + convertFile);
if (convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
}
S3에 정적 파일을 올리는 역할을 하는 S3Uploader 클래스이다. 이를 Service 영역에 둘 지, 아니면 다른 영역(utils, handlers 등)에 두고 사용할 지는 개인의 판단하에 로직을 정하고 사용하면 될 것 같다. 본인의 경우, domain에 util 이라는 디렉토리를 따로 생성해서 보관하고 있다. 정답은 없다.
코드를 보면 맨 처음에 AmazonS3Client를 @RequiredArgsConstructor 어노테이션으로 의존성 주입을 받는다. bucket의 이름으로 @Value("${cloud.aws.s3.bucket}")을 사용하고 이는 위에서 작성했던 S3Config.java파일에서 가져온다.
MultipartFile을 전달받아서 S3에 전달가능한 형태인 File을 생성하고, 전환된 File을 S3에 public 읽기 권한으로 전송한다. 그리고 로컬에 생성된 File을 삭제한 뒤, 업로드된 파일의 S3 URL 주소를 반환합니다.
위 코드에서 dirName은 AWS S3 버킷 내 디렉토리를 의미한다. 이 디렉토리 같은 경우 .yml 혹은 .properties 에서 default로 설정해 줄 수도 있지만, 로직 구현의 유연성을 위해서 따로 기재하지 않고 사용하는 서비스마다 다른 디렉토리로 지정하는 것이 옳다고 생각하여 위와 같이 매개변수로 받도록 하였다. 정답은 없다.
어렵다. 정보검색이 제일 힘들다. 그치만 재밋다.
https://studyandwrite.tistory.com/498
https://develop-writing.tistory.com/128
[TIL#32-2] testyPie] CICD를 위한 세팅 (0) | 2024.02.13 |
---|