회원가입 기능을 구현할 때, 들어가는 정보로 이메일, 비밀번호, 닉네임 그리고 프로필 사진을 넣기로 했다. 이미지 storage는 AWS S3을 사용하기로 했고, 이에 맞는 ImageService를 만들어 회원가입 기능을 구현했다.
API를 구현하고 Swagger에서 이미지 파일이 S3 버킷에 잘 저장되나 테스트하고 있었는데, 같은 이미지 파일로 두 번 회원가입을 했는데도 버킷에는 이미지 파일이 하나만 있었다.
파일 구분을 파일명으로 하는 것 같았다. 찾아보니 같은 이름의 이미지를 한 번 더 저장할 경우, 새로 저장되는 이미지 파일로 덮어씌워 진다고 한다. 이렇게 되면 두 회원이 하나의 프로필 사진 파일을 공유하게 되는 것이므로, 만약 한 쪽에서 프로필 사진을 삭제하게 된다면 나머지 한 회원도 영향을 받게 된다.
절대 있으면 안되는 일이므로! 같은 이미지 파일이어도 중복 저장 가능하게 만들 방법이 필요했다.
S3에 파일을 업로드 하는 기존 방법은 아래와 같았다.
public String saveImage(MultipartFile multipartFile){
if(multipartFile == null) return null;
String fileName = multipartFile.getOriginalFilename();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(multipartFile.getSize());
metadata.setContentType(multipartFile.getContentType());
try {
amazonS3.putObject(bucket, fileName, multipartFile.getInputStream(), metadata);
} catch (IOException e) {
throw new RuntimeException(e);
}
return amazonS3.getUrl(bucket, fileName).toString();
}
만약 profileImage.png를 업로드하면 AWS S3에 그대로 profileImage라는 이름으로 파일이 저장되는 것이다. S3는 파일 이름으로 파일을 구분하기 때문에, 같은 파일도 중복 저장 가능하게 하려면 이름을 다르게 만들어서 업로드 할 필요가 있다.
생각한 방법으로는 기존의 파일명에 겹치지 않을 법한 string을 붙여서 저장하는 것이다. 처음엔 모든 유저가 겹칠 수 없는 정보로 email을 이미지 파일명 앞에 붙일까 했는데, 이보단 random UUID를 사용해서 중복되지 않는 파일명을 만드는게 확실한 방법일 것이라 판단했다.
public String saveImage(MultipartFile multipartFile){
if(multipartFile == null) return null;
String originalImageName = multipartFile.getOriginalFilename();
String fileName = UUID.randomUUID().toString().concat(Objects.requireNonNull(originalImageName));
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(multipartFile.getSize());
metadata.setContentType(multipartFile.getContentType());
try {
amazonS3.putObject(bucket, fileName, multipartFile.getInputStream(), metadata);
} catch (IOException e) {
throw new RuntimeException(e);
}
return amazonS3.getUrl(bucket, fileName).toString();
}
랜덤한 UUID를 기존 파일명 앞에 붙여서 업로드 하기로 했다. 저장된 프로필 이미지 url을 회원 DB에 올려두면 끝!
이제 같은 profileImage.png로 회원가입을 진행해도 두 개의 파일이 중복 저장 가능하게 됐다!