인스타그램 클론 프로젝트-(11)
- 댓글 기능 구현
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 창에 오류메세지를 띄우도록 설정한다. (서버단에서 처리)
그리고 프론트 단에서도 처리한다.
Author And Source
이 문제에 관하여(인스타그램 클론 프로젝트-(11)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@claudia/인스타그램-클론-프로젝트-11저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)