인스타그램 클론 프로젝트-(6)

Claudia Hong·2021년 8월 16일
0

Project

목록 보기
12/26

디폴트 프로필페이지 구현하기

  1. 사진 등록하기

1) 모델 완성하기
(1) 도메인
id
caption : 업로드할 때 붙을 내용
postImageUrl : URL이라고 하는 이유는, 사진을 업로드 한다 >> 사진을 전송 받고 그 사진을 서버의 특정 폴더에 저장한다. 그리고 경로를 DB에 INSERT한다.
user : 그 사진을 누가 업로드했는지 알아야 하므로.
user와 image의 연관관계
1 1
1 N
user가 1 인 관계이므로 ManyToOne 관계이다.
DB에 저장될 때는 오브젝트 형태로 저장이 되므로 >>FK로 지정해준다.

creatDate : DB에는 항상 시간이 들어가야 한다.

(2) 레포지토리 만들기

2) 컨트롤러

ImageController에서 imageUpload 메소드에서 PostMapping으로 받아야 할 것을 먼저 생각해보자
Caption 그리고 이미지 파일!! (URL아님) 을 받아야 한다. >> 앞서 만든 도메인으로는 파일을 받을 수 없으므로 요청을 위한 DTO를 만들어야 한다.

파일은 MultipartFile 을 타입으로 해서 만든다.

36줄 : imageUpload 파라미터로 DTO를 넣어주고, 이미지를 업로드 하기 위해서는 로그인이 된 유저 정보가 필요 >> @AuthenticationPrincipal PrincipalDetails principalDetails

38줄 : 서비스를 호출한다. (메소드의 파라미터들과 서비스 메소드의 파라미터가 바인딩 되어 걸릴 것.)

40줄 : 사진을 업로드 한 후, 유저 개인의 기본페이지로 돌아가야 한다. 그때의 주소를 보면 /user/1(user의 id) 이므로 principalDetails에서 유저 정보의 id를 가져와서 넣어주도록 한다.

컨트롤러는 사용자로부터 데이터를 받고 서비스를 호출하는 걸로 깔끔하게 끝나야 한다. 실제 로직은 서비스에서 구현한다.

3) 서비스

(1) UUID(Universally Unique IDentifier 범용 유일한 식별자)

서비스에서 로직을 짤 때, 이미지 파일의 이름을 가지고 저장을 하게 된다. 이때, 동일한 이름의 이미지 (예: 1.jpg 와 1.jpg)를 저장하게 되는 경우 문제가 발생한다.

서버의 폴더에 이미지를 저장하면 DB에 경로(/upload/1.jpg)가 저장되는데 동일한 이름이 하나가 더 저장이 되면 원래 있던 파일을 덮어 씌우게 된다. >> 문제 발생

사용자는 서버에 어떤 파일이 있는지 모르기 때문에 서비스에서 동일한 이름의 파일을 구분해줘야 한다. 그때 필요한 것이 UUID이다.

네트워크 상에서 고유성이 보장되는 id를 만들기 위한 표준 규약

유일성이 보장된다. 그럼에도 아주아주 작은 확률로 동일한 UUID가 생길 수 있기 때문에, UUID+_+파일명 이렇게 파일명을 저장한다.

이미지파일 이름55204617-4806-44ff-a644-2bae3532dd55_백엔드개발 과정.jpg

이미지 파일 이름을 만들었으므로 저장을 하기로 한다.

Path 를 이용해서 실제로 어디에 저장을 할 것인지를 정해줘야 한다.

<apllication.yml>

29~31줄 : 서블릿의 멀티파트로 사진을 받겠다.(enabled :true)
32줄 : 파일 최대크기는 2MB로 제한을 두겠다.

40줄 : 파일의 저장경로를 정해 놓고 위처럼 폴더를 실제로 만들어 준다.
경로를 yml 파일에 넣어서 지정하는 이유 : 서비스 안에 직접 넣으면 이후에 경로가 바뀔 일이 있을 때 모든 코드를 바꿔야 하고, 잘못 쓰게 되는 경우가 발생하므로.(끝에 꼭 / 넣어야 한다)

Path에 넣기 위한 경로 값을 가져오는 방법

{ } 안의 값은 yml에서 39줄의 file 40줄의 path 이다.

35~37줄 : try catch 로 묶어주고 Files.write(path, 실제 이미지 파일(DTO.getFile() 을 바이트화 하기 위해 .getBytes()를 붙여준다.), 마지막 옵션은 생략 가능) 트라이 문이 실행될때 파일을 쓴다(Write).

여기서 try catch를 갑자기 쓰는 이유??
통신 혹은 I.O(하드디스크의 기록하거나 읽을 때)가 일어날 때는 예외가 발생할 수 있다. (예, 1.jpg 파일을 읽고 싶은데 DB에 없을 경우 >> 런타임일 때만 발생하는 예외) 이를 예외처리를 해줘야 하기 때문에 사용한다.

++) View 단

21줄 : 액션과 메소드, enctype을 정해준다. 그런데 사진 설명의 경우 key=value 형태로 application/x-www-form-urlencoded 인데 문제는 사진은 바이트화 해서 바이트 형태이다. >> 두개 이상의 다른 타입의 데이터를 전송이 필요 >> multipart/form-data 타입 : 여러가지 종류의 타입을 묶어서 전송할 때 사용하는 타입이다.

<upload 폴더를 내부에 두지 않고 외부에 두는 이유는?>

프로젝트가 어떻게 돌아가는지부터 이해를 해야한다.
프로젝트 내부는 .java(코드) 파일들이 있다. ①서버실행 될 때 ②컴파일이 되는데 컴파일이란, 내부의 .java 파일들이 .class로 바뀌는 것을 말한다. .class 파일들을 포함해 프로젝트 안에서 만들어지는 모든 것들은 프로젝트 내의 ③Target이라는 폴더 안으로 들어간다. 그리고 Target 폴더 안의 .class 파일들을 포함한 모든 것들을 ④실행한다. (Target 폴더 안으로 사진 등 정적파일들이 포함=반영이 되어야 실행이 될 수 있다.)

Target 폴더 안에 .class, 정적파일 등 모두 집어넣는 행위를 deploy 한다 = 배포 라고 한다.

사진 등 정적파일은 용량이 있기 때문에 .class 파일보다 deploy하는데 시간이 걸린다. 이때, 프로필로 가는 시간이 내부의 업로드 파일을 deploy하는 시간보다 빨라서 시간차 문제가 발생할 수 있다.(페이지가 넘어갔는데 이미지 등이 deploy이 되지 않아서 엑박이 뜨는 경우 등)

정적파일 등이 담긴 폴더(upload 등)를 외부에 두면 deploy 될 필요가 없기 때문에 위의 시간차 문제가 발생하지 않는다. 찾을 때도 Target에서 찾는게 아니라 외부에 있으므로 움직이지 않기 때문에 엑박이 뜰 일이 없다.

(2) 이미지 테이블에 저장하기

45줄 : Image 객체 만들어주기 >>> 객체image와 imageUploadDto는 타입이 맞지 않기 때문에 DTO에서 toEntity()를 써서 바꾸도록 한다.

46줄 : image를 테이블에 저장하기 위해서는 image 객체를 넣어야 한다.

16~22줄 : toEntity() 함수를 사용해서 오브젝트로 만드는 과정이다.
19~20줄 : caption은 caption을 넣으면 되지만 DB에는 경로를 저장해야 하기 때문에 파일의 형태인 file도 안 되고, file.getOriginalFilename()도 넣어서는 안된다. >> postImageUrl을 넣는다.
21줄 : 저장할 때는 누가 업로드를 했는지가 필요하므로 user도 들어간다.

45줄 : image 객체에 imageFileName과 User 정보를 담는다.
DB에 imageFileName을 저장하고 경로를 지정해주지 않으면 못찾지 않을까?? >> yml에 경로가 있기 때문에 yml에서 가져오면 된다. 그렇기 때문에 DTO에서 파라미터로 postImageUrl과 user를 담아서 넘긴다.

4) 유효성검사

이미지를 넣지 않았을 때, 업로드 하면 에러가 발생하는 부분을 익셉션 처리 하기.

39줄 : @Vaild에 파일같은 멀티파트 타입을 어노테이션으로 유효성검사하는 기능이 없기 때문에 비었을 경우?를 강제로 만들어준다.
40줄 : 어떤 요청을 받아서 데이터를 응답하는(API) 것이 아니라 페이지를 응답할 것이므로 CustomVaildationException을 쓴다. (errorMap은 null값을 넣는다.)

22~28줄 : errorMap을 그대로 null을 넣어서 처리하면 에러가 뜸. >> 핸들러에서 분기를 해서 null일 경우에는 메세지만을 띄우도록 처리

0개의 댓글

관련 채용 정보