의존성 추가
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
cloud.aws.credentials.accessKey= 발급받은 IAM 키
cloud.aws.credentials.secretKey= 발급받은 IAM 키값
cloud.aws.s3.bucket=beatbuddy-s3-bucket= 버킷 이름
cloud.aws.region.static=ap-northeast-2 [버킷이 존재하는 리전]
cloud.aws.stack.auto=false AWS CloudFormation 자동 생성 x
@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean
public AmazonS3 amazonS3Client() {
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
return AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(region)
.build();
}
}
application.properties에서 설정한 값을 불러와 AmazonS3에 연결
@Slf4j
@RequiredArgsConstructor
@Component
@Service
public class S3Uploader {
private final AmazonS3 amazonS3Client;
private static final Logger logger = LoggerFactory.getLogger(S3Uploader.class);
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
public String upload(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
return upload(uploadFile, dirName);
}
// 파일 이름을 UUID로 변경
private String generateUUIDFilename(File file) {
String originalFilename = file.getName();
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
String uuidFilename = java.util.UUID.randomUUID().toString() + extension;
log.info("파일 이름 변경 : {}", uuidFilename);
return uuidFilename;
}
private String upload(File uploadFile, String dirName) {
String fileName = dirName + "/" + generateUUIDFilename(uploadFile);
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile); // 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)
return uploadImageUrl; // 업로드된 파일의 S3 URL 주소 반환
}
// s3에 업로드
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead) // PublicRead 권한으로 업로드 됨
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}
private void removeNewFile(File targetFile) {
if(targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
}else {
log.info("파일이 삭제되지 못했습니다.");
}
}
// MultipartFile -> File 로 변환
private Optional<File> convert(MultipartFile file) {
try {
File convertFile = new File(file.getOriginalFilename());
if (convertFile.createNewFile() || convertFile.isFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
} else {
log.error("파일 생성에 실패했습니다. 파일이 이미 존재합니다: {}", convertFile.getName());
return Optional.empty();
}
} catch (IOException e) {
log.error("MultipartFile을 File로 변환하는데 실패했습니다.", e);
return Optional.empty();
}
}
// S3에서 파일 삭제
public void delete(String dirName) {
amazonS3Client.deleteObject(new DeleteObjectRequest(bucket, dirName));
log.info("S3 bucket에서 File {} 삭제.", dirName);
}
}
@Autowired
private S3Uploader s3Uploader;
해당하는 Service에 S3Uploader 의존성 주입
imageFileUrl = s3Uploader.upload(imageFile,"feed-image");
서비스 로직의 파라미터로 받은 MutilpartFile 과 bucket에 생성한 폴더명을 s3Uploader에 전송.
레퍼런스