GDSC 1차 프로젝트(네컷앨범 고도화) 세 번째 게시물입니다.
S3 버킷 생성, IAM 계정 생성 등에 대한 부분은 생략하겠습니다.
https://docs.aws.amazon.com/ko_kr/sdk-for-java/v1/developer-guide/examples-s3-objects.html
위 링크의 AWS SDK for Java1.x 공식 문서를 참조하였습니다. 예제 코드를 바탕으로 서비스를 구현하였습니다.
앱에 사진 수정 기능은 구현하지 않으므로, 수정을 제외한 기능을 서비스로 구현하였습니다.
S3ServiceImpl.java
@Slf4j
@RequiredArgsConstructor
@Service
public class S3ServiceImpl implements S3Service {
private final AmazonS3 amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
@Override
public String upload(String base64, String fileName) {
boolean result = decode(base64, fileName);
System.out.println(result);
File uploadFile = new File(fileName);
amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, uploadFile).withCannedAcl(CannedAccessControlList.PublicRead));
// remove new temp file
if (uploadFile.delete()) {
log.info(uploadFile.getName() + "로컬 이미지 파일이 삭제 되었습니다.");
} else {
log.info(uploadFile.getName() + "로컬 이미지 파일이 삭제 되지 못했습니다.");
}
return amazonS3Client.getUrl(bucket, fileName).toString();
}
}
AmazonS3 amazonS3Client
: S3 사용을 위한 클라이언트입니다.String bucket
: .yml에서 버킷이름을 가져옵니다.String upload()
: 안드로이드 클라이언트로부터 받은 base64문자열을 디코딩합니다.amazonS3Client.putObject()
: S3 버킷에 이미지 파일을 업로드합니다.S3ServiceImpl.java
@Slf4j
@RequiredArgsConstructor
@Service
public class S3ServiceImpl implements S3Service {
...
private final TransferManager transferManager;
...
@Override
public void downloadDirectory(String prefix, String localDirectoryPath) {
File localDirectory = new File(localDirectoryPath);
try {
MultipleFileDownload downloader = transferManager.downloadDirectory(
bucket, prefix, localDirectory);
downloader.waitForCompletion();
log.info(downloader.getDescription());
} catch (Exception e) {
log.info(e.getMessage());
}
}
}
TransferManager transferManager
: S3 객체 다운로드를 위해 사용합니다.downloadDirectory()
: 다운로드 받을 로컬 주소를 지정해 S3에서 디렉토리의 개체를 전부 다운로드합니다.S3ServiceImpl.java
@Slf4j
@RequiredArgsConstructor
@Service
public class S3ServiceImpl implements S3Service {
...
@Override
public void delete(String key) {
if (amazonS3Client.doesObjectExist(bucket, key)) {
try {
amazonS3Client.deleteObject(new DeleteObjectRequest(bucket, key));
log.info(key + ": s3 객체 삭제에 성공했습니다.");
}
catch (Exception e) {
log.info(key + ": s3 객체 삭제에 실패했습니다.");
log.info(e.getMessage());
}
}
}
delete()
: S3 객체의 key를 전달 받아 버킷의 객체를 삭제합니다.amazonS3Client.doesObjectExist()
: 해당 key의 객체의 존재 여부를 확인한 후 삭제합니다.사실 delete() 구현에는 굉장히 시간을 많이 썼습니다... 다름아닌 권한 문제 때문이었습니다. 블로그에 많이 적힌 것들 처럼 S3 버킷 - 권한 - 버킷 정책
JSON 파일을 수정해서 모든 권한을 주기도 하고, delete 권한만 따로 주기도 하고 무슨 짓을 해도 안 되던 오류가 발생해서 코드도 고쳐보고 다 했으나 되지 않았습니다...
그렇게 삽질을 하던결과 IAM 계정 자체의 권한 문제였습니다. 저는 IAM 계정에 AmazonS3FullAccess
정책을 연결했으나, 그 이전에 생성 시 연결된 다른 정책에 삭제 권한을 Deny하는 정책이 있어 권한이 없던 것이었습니다. 다음부턴 이런 권한 충돌이 일어나지 않는지 잘 살펴보고 IAM 정책 설정을 해야한다는 것을 깨달았습니다. ㅠㅠ