ASW S3 SDK로 빠르고 간단하게 사용할 수 있습니다.
이때 메타 데이터의 키값은 소문자로 변경됩니다.
// 이미지 path를 만들 유니크한 객체 2개, 이미지를 받음
public void uploadPlantImage(User user, Plant plant, ByteBuffer imageBuffer) {
// 이미지를 분별할 해시 값 생성
String imageHash = cloudFlareR2Utils.calculateImageHash(imageBuffer);
// 이미지의 위치 지정
String imageType = "thumbnail";
String filePath = user.getEmail() + "/" + plant.getId()
+ "/" + imageType + "/image.jpg";
String fileName = storagePointUri + filePath;
plant.setImgUrl(fileName);
logger.info("img URL :: {}", plant.getImgUrl());
// R2에 Object 전송
putObjectToR2(imageBuffer, imageHash, filePath);
}
private void putObjectToR2(ByteBuffer imageBuffer, String imageHash, String filePath) {
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucketName)
.contentType("image/jpeg") // MIME 타입 설정
.metadata(Map.of("Content-Disposition", "inline", "image-hash", imageHash))
.key(filePath).acl(ObjectCannedACL.PUBLIC_READ)
.build();
s3Client.putObject(putObjectRequest, RequestBody.fromByteBuffer(imageBuffer));
}
public void editPlantImage(User user, Plant plant, ByteBuffer imageBuffer) {
String imageType = "thumbnail";
String filePath = user.getEmail() + "/" + plant.getId() + "/" + imageType + "/image.jpg";
String fileName = storagePointUri + filePath;
// 해시값 생성
String imageHash = cloudFlareR2Utils.calculateImageHash(imageBuffer);
String existingImageHash = retrieveImageHashFromR2(filePath);
// 이미지 해시 비교
if (!imageHash.equals(existingImageHash)) {
logger.info("Image hash Changed now : {}, exist : {}", imageHash, existingImageHash);
// 이미지 업로드
uploadPlantImage(user, plant, imageBuffer);
// 이미지 다르면 캐시 삭제
cloudFlarePurgeCache.purgeCache(fileName);
}
}
// 존재했던 이미지의 해시값 찾기
public String retrieveImageHashFromR2(String filePath) {
try {
HeadObjectResponse response = s3Client.headObject(HeadObjectRequest.builder()
.bucket(bucketName)
.key(filePath)
.build());
return response.metadata().get("image-hash");
} catch (S3Exception e) {
throw new RuntimeException("Failed to retrieve image hash from R2", e);
}
}
키값을 받고 안에 있는 객체들을 모두 삭제합니다.
public void deletePlant(Long plantId, String userEmail) {
try {
String filePath = userEmail + "/" + plantId;
// plantId의 하위 키값들을 모두 가져올 준비
ListObjectsRequest listObjects = ListObjectsRequest.builder()
.bucket(bucketName)
.prefix(filePath) // userEmail/PlantId/
.build();
ListObjectsResponse listObjectsResponse = s3Client.listObjects(listObjects);
// 하위 키를 사용해 모두 삭제
for (S3Object object : listObjectsResponse.contents()) {
DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder()
.bucket(bucketName)
.key(object.key())
.build();
s3Client.deleteObject(deleteRequest);
}
} catch (S3Exception e) {
// 로그 기록, 예외 처리 로직
throw new RuntimeException("파일 삭제 중 오류가 발생했습니다.", e);
}
}
Cloudflare R2의 최대 장점은 아웃바운드 Get의 비용과 저장비용이 저렴한 것입니다.
따라서 최대한 장점을 살리기 위해선 Put을 줄여야 하기 때문에 메타태그를 사용해 수정해야할 일을 줄인다면 더 저렴하게 이용할 수 있습니다.