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

  1. 댓글 기능 구현

1) 댓글 쓰기

(1) 모델 만들기

댓글에 필요한 정보(여러가지)
(유저아이디) + (댓글내용) + (시간) >>> 오브젝트 >>> 테이블

이미지에는 한건의 댓글만이 달리는게 아니라 여러건이 달린다. >> Image.java 안에 넣을 수 없다.

<연관관계>
댓글 유저 하나의 댓글은 한명이 쓴다
1 N
댓글 유저 한명의 유저는 여러개의 댓글을 쓸 수 있다.
N 1

comment.java의 User는 ManyToOne

댓글 이미지 하나의 이미지는 여러개의 댓글이 달릴 수 있다.
N 1
하나의 댓글에 이미지는 몇개까지?? >> 말이 안됨

comment.java의 Image는 ManyToOne

41,45줄 : Eager인 이유 >> 댓글을 하나 Select해올 때, 그 댓글에 해당하는 유저정보와 이미지정보가 1개씩 밖에 없으므로 같이 Join해 와도 상관이 없다. (하나 Select할 때 딸려오는게 여러개일 경우는 Lazy)

JpaRepository<타입(Comment), Integer>

(2) JS-Ajax 만들기

샘플데이터가 들어있는 JSP 화면 중 수정이 필요한 부분

61줄 : 댓글 내용은 imageId값으로 찾아 들어가서 그 안의 text를 찾으면 된다.
77줄 : User와 Image의 데이터를 날려야하므로 addComment()안에 파라미터로 imageId를 넣는다. '누가' 적었는지는 굳이 넣지 않아도 된다. 세션값이 찾을 수 있음.

댓글을 써서 addComment >> DB에 내용 insert >> storyCommentList를 찾아서 그 안에 append

153~4줄 : data.content >> 댓글 쓴 내용 / imageId도 같이 날린다.

157~9줄 : 내용이 null이면 넘어가지 못하게 return한다.

162~172줄 : ajax 통신
165줄 : data를 string으로 만들어서 json 타입으로 던지도록 한다.
166줄 : 내가 보내는 데이터에 대한 설명이 필요함
168줄 : res에는 항상 통신의 결과를 남긴다.

18줄 : prpend 미리 앞에 넣는 것/ append 뒤에 넣는 것 >> 최신 댓글이 맨 앞에 나오게 (아래 그림 참고)

186줄 : 그리고 commentinput을 비워준다.

(3) DTO

imageId와 content를 받을 때, Comment로 받을 수는 없다. >> dto를 만든다.

toEntity가 필요없다.
이유 >>

(4) Service, Controller

  • Controller (ajax로 통신할 것이므로 apiController이다.)

28줄 : CommentDto는 x-www-formencoded-url? 그 타입이 아니고 json 데이터라서 앞에 @RequestBody를 붙여서 받는다.
29줄 : 세션에서 로그인한 userId를 뽑아오기 위해 파라미터로 넣는다.
31~2줄 : 저장하기 구현
34줄 : 만들어서 넣는 건 CREATED로

  • service

comment 객체를 만들어서 insert하기 어렵다. >> Repository에서 쿼리를 짜서 insert를 한다.

INSET INTO comment(content, imageId, userId, createDate) VALUES(:content. :imageId, :userId, now())

리턴할 것 >> INSERT 후 만들어진 객체를 리턴

그런데 이렇게 하면, 500 에러가 뜬다.

이유 >> @Modifying은 int로 리턴하거나 void 일때만 쓸 수 있다. 그러나 그 리턴타입으로는 content를 전달 할 수 없고, comment의 PK가 없어지기 때문에 이후에 댓글 삭제하기 기능 구현이 불가하다.

그러므로 JpaRepository의 save 기능을 써서 구현해야한다.

28줄 : 코멘트 객체를 만든다.
29~31줄 : 그리고 하나씩 변수값을 넣는다? >> imageId가 아니라 Image를 넣어야 하고 userId가 아니라 User를 넣어야 하는데 그러기 위해서는 Select를 또 해줘야 한다. ((복잡))

<간단하게 하는 Tip!!>
22, 25줄 : 가짜객체를 만들고 그걸 넣는다.
23, 26줄 : 그리고 그 가짜객체에 id 값을 불러와 넣는다.
30, 31줄 : 그리고 그걸 setImage(), setUser() 안에 넣는다.

객체를 만들 때, id값만 담아서 INSERT 할 수 있다!
대신 return 시에 두 객체에는 id 값만 가지고 있는 빈 객체를 리턴 받는다.

댓글 앞에 붙는 username은? 세션값? 위험함 >> UserRepository를 이용해서 가져오는 방법으로 바꾼다.

(5) 뷰 랜더링

User 정보 안의 images는 ignore 한다.(무한참조 방지)

169줄 : res 안에는 쓰기에 성공한 댓글 내용들이 담겨져 있다.
186줄 : input 필드를 깨끗하게 비워준다.

여기까지 하면 댓글이 입력 및 인서트는 되는데, 새로고침 시 화면에서 지워진다. >> Story 페이지로 올 때 댓글도 들고와서 화면에 뿌려줘야 한다. >> 양방향매핑

57줄 : 무한참조(IOException) 방지
58줄 : 컬렉션이면 굳이 생각 안해도 OneToMany이다.
+) 연관관계의 주인이 아니다. (Comment와 image의 관계에서 FK는 Comment의 image에 만들어진다. FK에 대한 자바변수를 적어준다.)
+) fetchType은 Lazy >> getter가 호출될 때만 불러오도록 한다. (인기 페이지에는 댓글이 필요 없다)

정렬을 해줘야 한다. comment는 image를 select 할 때, 가져온다. @OrderBy (jvas.persistence 것) >> JPA를 이용해서 Select할때 가능

2) 댓글 삭제하기

댓글 삭제버튼은 댓글을 쓴 본인에게만 보이고 삭제 기능이 되어야 한다.

(1) JS

getStoryItem()에서 principalId를 받아오지 않고 있음.

  • principalId 가져오는 방법

header.jsp에서 js로 잠깐 담아두면 된다.

어디에서든지 js에서 꺼내쓸 수 있다.

(72줄부터)

74줄 : 버튼에 이벤트를 발생시키도록 한다. >> Onclick / 삭제할 때 들고와야할 것은? Comment의 id값

(2) Controller, Service

추가적인 기능을 더 붙이다보면 터질 수도 있음. 그럴 땐 try catch로 잡으면 됨. CustomApiException은 데이터를 리턴하는 컨트롤러의 익셉션이고 CustomException은 html을 리턴하는 컨트롤러의 익셉션이다.

버튼 Onclick으로 이벤트를 발생시키도록 한다.

3) 유효성 검사

CommentDto의 Validation을 한다.

  • NotNull : null값 체크
  • NotEmpty : 빈값이거나 null 체크
  • NotBlank : 빈값이거나 null 체크 그리고 빈공백(스페이스)까지

35줄 : CommentApiController에 @Valid를 하고 뒤에 바로 매핑되도록 BindingReuslt를 넣는다.

38~45줄 : if문으로 CustomVaildationException 처리를 한다.

JS에서 공백일 때 댓글게시 버튼을 누르면 alert 창에 오류메세지를 띄우도록 설정한다. (서버단에서 처리)

그리고 프론트 단에서도 처리한다.

좋은 웹페이지 즐겨찾기