Articket의 리뷰 기능에서는 사용자가 리뷰를 작성하면서 최대 3개의 이미지를 등록할 수 있도록 구현했다.
이미지는 파일 자체를 DB에 저장하는 것이 아니라 서버의 upload/review 폴더에 저장하고, DB에는 해당 파일의 정보를 저장하는 방식으로 구현했다.
처음에는 이미지 파일을 DB에 저장하는 것과 이미지 정보를 DB에 저장하는 것이 헷갈렸다.
MultipartFile은 HTTP 요청으로 전달된 파일을 Spring에서 다루기 위한 객체이고, ReviewImage는 저장된 이미지의 정보를 DB에서 관리하기 위한 Entity로 구분했다.
MultipartFile
↓
실제 파일 저장
↓
ReviewImage 생성
↓
REVIEW_IMAGE 저장
String originalFilename = image.getOriginalFilename();
String uuid = UUID.randomUUID().toString();
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
String savedFilename = uuid + extension;
Path savePath = uploadPath.resolve(savedFilename);
image.transferTo(savePath);
String imageUrl = "/upload/review/" + savedFilename;
ReviewImage reviewImage = new ReviewImage(review, originalFilename, savedFilename, imageUrl, i + 1);
reviewImageRepository.save(reviewImage);
원본 파일명을 그대로 기재할 경우 동일한 파일이 업로드 되었을 시 충돌이 발생할 수 있다.
이를 해결하기 위해 UUID를 사용하여 처리를 진행했다.
그리고 MIME를 추려내기 위하여 subString(), lastIndexOf() 메서드를 활용하여 .jpg, .jpeg, .webp, .png 만을 선별하였다.
// 이미지 갯수 검증
if (images != null && images.size() > 3) {
throw new IllegalArgumentException("리뷰 이미지는 최대 3개까지 등록 가능합니다.");
}
// 이미지 파일 검증
if (images != null) {
for (MultipartFile image : images) {
if (image.getSize() > 5 * 1024 * 1024) {
throw new IllegalArgumentException("이미지는 5MB 이하만 등록 가능합니다.");
}
String contentType = image.getContentType();
if (!List.of("image/jpeg", "image/png", "image/webp").contains(contentType)) {
throw new IllegalArgumentException("JPG, JPEG, PNG, WEBP 이미지만 등록 가능합니다.");
}
}
}