[포토그램] 5. 프로필 페이지 - 이미지 업로드

kiwonkim·2021년 10월 3일
0

이전 포스팅

Subscribe 클래스로 JPA를 활용해 DB의 모델을 구현하고,
SubscribeApiController 에서 PathVarialbe을 toUserId로. 세션Id를 formUserId로 하여 SubscribeService의 파라미터로 넘겨주었다.
SubscribeService는 SubscribeRepository에서 짜놓은 네이티브쿼리를 이용해 구독하기와 구독취소를 진행하고.
UniqueConstratins 가 위배되면 CustomApiException 을 발동시켜 메시지를 담은 CMRespDto를 반환하게 된다.

이제 구독과 비슷한 방식으로 모델을 설계하여 이미지를 업로드하는 과정을 진행해보자



DB에 이미지 저장

유저와 이미지의 관계 파악

하나의 이미지는 한 사람이 업로드 (1 : 1)
한 사람은 여러 이미지를 업로드 가능 (1 : N)

따라서 유저 : 이미지 = 1 : N


DB에 사진을 저장할 수 있을까?

유저가 사진을 업로드하면 이를 DB에 저장하여야 한다.
그런데 사진은 용량이 커 사진 자체를 저장하면 병목현상이 생기고, DB 용량 낭비가 심해진다.
따라서 보통 서버단에 사진파일(1.jpg)를 저장하고, 경로를 DB에 저장하여 사용한다.


왜 class가 있는 폴더가 아닌 별도의 폴더에 사진을 저장할까?

.java가 존재하는 폴더는 컴파일러에 의해 컴파일되며 .class의 정적파일로 변환된다.
업로드한 이미지 파일이 여기 존재할 경우 컴파일은 되지 않지만, 정적파일로 변환되는 일련의 과정을 거치게 되고, 이때 병목현상이 생긴다.
병목현상을 방지하기 위해 별도의 디렉토리에 이미지파일을 저장한다.



Image 모델 설계

PK인 id.
사진 캡션을 의미하는 catpion
이미지 파일이름을 의미하는 postImageUrl.
FK인 User. (사진 업로드한 UserId를 의미)

유저 : 사진 = 1: N 이므로 @ManyToOne을 추가하였다.


JPA 이용 ImageRepository 구현.


Upload.jsp

upload.jsp이다. 사진(File)과 설명(JSON)을 함께 넘겨주게 되는데.
이때 둘의 자료형이 다르므로 enctype을 x-www-form-urlencoded 가 아닌 multipart/from-data로 설정해야한다.
그러면 file과 caption을 컨트롤러에게 넘겨주게된다.



ImageUploadDto

사용자의 폼태그 입력값을 저장할 ImageUploadDto이다.
file, caption을 갖으며.
후에 Image로 변환하기 위해 Builder을 활용한 toEntity 메서드를 갖는다.



ImageController

ImageController이다.
폼태그 입력값을 ImageUploadDto로 받고.
File이 없을경우 CustomValidationException을 터뜨리며.
제대로 된 입력일 경우 ImageService의 사진업로드 메서드를 수행한다.

최종적으로 이미지 업로드 후 원래 사용자 페이지로 redirect 시킨다.



ImageService

ImageService이다. 하나하나 살펴보자면


Repository 를 DI받고.
Upload 폴더 경로를 application.yml에서 가져와 uploadFolder에 저장한다. 이 때 @Value 어노테이션을 사용한다.
그냥 문자열로 해도 되지만, 재사용성을 높이기 위해 application.yml에서 가져와 사용하였다.


사진이름을 사용자가 캡션으로 올릴 것이나, 여러 사용자에게 받으면 중복될 수 있다.
이를 방지하기 위해 고유성 보장되는 UUID를 발급받고.
UUID_파일명(캡션) 으로 파일명을 저장해놓는다.


폴더경로 + 파일명으로 최종 Path를 Path변수에 저장하고.
Files.write를 통해, 파라미터로 전달받은 imageUploadDto 의 이미지 File을 Bytes화 하여 Path에 저장한다.
이 때 I/O에서 예외가 발생할 수 있기에 예외처리를 수행한다.


마지막으로 전달받은 imageUploadDto를 DB에 저장해야 하는데, imageRepository의 매개변수로는 Image만 올 수 있다.
따라서 Builder를 사용한 toEntity로 ImageUploadDto -> Image 를 수행하고 save를 진행한다.



수행결과

upload 페이지에서 사진을 업로드하면

C:/workspace/springbootwork/upload 에 "UUID_파일이름"으로 파일이 생성되고.

DB에 입력캡션, UUID_파일이름, 업로한유저ID 가 저장됨을 알 수 있다.



정리

수행과정

  1. image/upload 로 들어가면 GetMapping으로 upload.jsp를 반환한다.

  2. upload.jsp에서 사진, 캡션을 업로드하면 form 태그 입력결과가 /image로 보내진다.

  3. PostMapping 으로 /image 에서 파일이 없을경우 예외를 터뜨리고, 파일이 있으면 imageService의 사진업로드 메서드를 호출한 뒤 redirect로 원래 페이지로 돌아간다.


구현

  1. Image Entity를 설계하고 ORM 을 이용해 Image 클래스 생성 및 DB에 엔티티를 생성한다. 또한 JPA이용 ImageRepository도 생성한다.

  2. ImageService에서 파라미터로 받은 ImageUploadDto의 파일ID에 UUID를 붙여 독자적인 ID를 만들고. 서버의 Upload 폴더에 이름을 독자적ID로 하여 파일을 저장한다.

  3. ImageService에서 DB에도 저장해야하는데, 이때 파라미터로 Image만 받으므로. Builder를 써서 ImageUploadDto -> Image를 진행하고. ImageRepository.save로 DB에 저장한다.

  4. ImageController에서는 ImageService로 디렉토리 저장 & DB 저장을 수행한다.

0개의 댓글

관련 채용 정보