Wanna be Brilliant Full-Stack Developer
2/18 SpringBoot Comment 모델 만들기 본문
이번시간에는 댓글을 만들어보려고한다!
1. Comment 모델 만들기
2. Comment 레파지토리 만들기
3. Comment 서비스 만들기
4. Comment API 컨트롤러 만들기
댓글이라는것을 봤을떄 댓글의 내용만 있으면 안된다. 언제썼는지 시간과 ,누가썼는지도 확인할 수 있어야한다
댓글 하나는 여러가지 데이터들이 모여서 만들어진다.
이런것들은 무조건 오브젝트이다. 일반 자료형이 아니라 String 값으로 못만든다.
이런것들은 다 테이블로 만들어줘야한다.
성별에 대한 정보가 필요하면 성별은 남아니면 여 이것만 들어갈수 있기 떄문에 이건 하나의 String으로 표현할 수 있다. 그러면 user테이블안에 쏙 들어가면된다.
하지만 댓글이라는건 이미지에 댓글이 달리지만 댓글이 이미지 테이블에 넣어질수가 없다. 한건이 아니니까
만약에 댓글에 내용만 있다면 이 이미지에다가 하나 추가해서 할수 도있을것인데
만약에 image.java에 private String replyContent이렇게 선언을 해버리면 이렇게 추가하면 문제가 머냐면
하나의 이미지에 댓글이 하나만 달리는것이 아니라 여러개가 달릴수 있어야한다.
테이블을 설계 할떄 내가 만들어야할것들이 있는데 댓글은 하나의 데이터로 만들어지지가 않는다.
댓글은 내용과 시간 ,누가적었는지도있어야하고 ,어떤 이미지에 댓글이 적혀있는지도 알아야하는데
이러한 여러가지가 필요할때는 무조건 오브젝트로 나와야하고 테이블로 나와야한다.
이 테이블이 나오는 경우에는 연관관계를 생각해야한다!
package com.cos.photogramstart.domain.comment;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PrePersist;
import com.cos.photogramstart.domain.image.Image;
import com.cos.photogramstart.domain.likes.Likes;
import com.cos.photogramstart.domain.user.User;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(length =100, nullable = false)
private String content;
private User user;
private Image image;
private LocalDateTime createDate;
@PrePersist
public void createDate() {
this.createDate = LocalDateTime.now();
}
}
한명의 댓글은 한명이 쓰는거고, 한명의 유저는 댓글을 여러개 쓸수 있다.
커멘트가 N이고 유저가 1이다.
하나의 이미지를 댓글이 몇개까지 일수있는가 제한이 없다. 1:N이다.
package com.cos.photogramstart.domain.comment;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import com.cos.photogramstart.domain.image.Image;
import com.cos.photogramstart.domain.likes.Likes;
import com.cos.photogramstart.domain.user.User;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(length =100, nullable = false)
private String content;
@ManyToOne(fetch = FetchType.EAGER)
private User user;
@ManyToOne(fetch = FetchType.EAGER)
private Image image;
private LocalDateTime createDate;
@PrePersist
public void createDate() {
this.createDate = LocalDateTime.now();
}
}
댓글을 하나 셀렉트할때 유저정보와 이미지정보는 한개밖에 없다. 그래서 조인해서 끌고와도 DB에 크게 무리가 없다.
반대로 보면 유저를 보면 한명의 유저를 셀렉트할때 이 유저가 만든 모든 이미지를 가져오는것이 Eager이면 유저 셀렉트 할떄마다 이미지를 계속 들고와 그 많은것들을
근데 어떤 유저 정보 페이지를 갈떄 유저 수정페이지를 갈때는 이미지는 안나와도되니까 Lazy이다. 여러개는 LAzy는 페치전략이 잡혀있다. 내가 먼가를 하나 셀렉트 할떄 딸려오는것들이 많으면 기본전략이 Lazy이다.
내가 하나를 셀렉트할때 딸려오는것이 하나면 기본전략이 Eager이다.
@JoinColumn(name ="usrId")
@ManyToOne(fetch = FetchType.EAGER)
private User user;
@JoinColumn(name ="imageId")
@ManyToOne(fetch = FetchType.EAGER)
private Image image; 애들은 이렇게 데이터베이스에 컬럼명으로 만들어질것이다.!
Comment 서비스와 컨트롤러를 만들것이다 !
package com.cos.photogramstart.web.api;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.cos.photogramstart.service.CommentService;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@RestController
public class CommentApiController {
private final CommentService commentService;
@PostMapping("/api/comment")
public ResponseEntity<?> commentSave() {
return null;
}
@DeleteMapping("/api/comment/{id}")
public ResponseEntity<?> commentDelete(@PathVariable int id) {
return null;
}
}
댓글 쓰기 할때는 어떤사람이 썼는지도알아야한다! 먼가를 또 받아야한다.
Stroy.js를 수정하고 데이터를 어떻게 전송하는지를 보고 이 컨트롤러를 완성하겠다!
<div class="sl__item__input">
<input type="text" placeholder="댓글 달기..." id="storyCommentInput-1" />
<button type="button" onClick="addComment()">게시</button>
</div>
여기 댓글달기할때 id가 1로되어있으면 애가 반복되면서 storyCommentInput-1로 되면서 오류가난다!
그래서 애를
<div class="sl__item__input">
<input type="text" placeholder="댓글 달기..." id="storyCommentInput-${image.id}" />
<button type="button" onClick="addComment()">게시</button>
</div>
이렇게 수정해주면 게시물마다 그 게시물을 올린 아이디의 번호로 나올것이다.
우리가 댓글을 쓸떄 코멘를 보면 내용과 유저정보와 이미지가 있어야지 인서트할수있다.
아직 커멘트에 유저랑 이미자아이디가 안날라가고있다.
<div class="sl__item__input">
<input type="text" placeholder="댓글 달기..." id="storyCommentInput-${image.id}" />
<button type="button" onClick="addComment(${image.id})">게시</button>
</div>
그리고 멀 날려야하냐면 누가 적었는지를 날려야하는데 누가적었는지는 안날려도된다
왜냐하면 세션값 찾으면되니까! 로그인 한사람이 글을 적을거니까
addComment 함수로 가게되면?
내가 댓글을 써고 addCOmment를 하게되면 DB에나 서버쪽에 내용이 전송되고 다되고 나면 storyCommentList-1을 찾아서 append를 해야한다!
// (4) 댓글쓰기
function addComment(imageId) {
let commentInput = $(`#storyCommentInput-${imageId}`);
let commentList = $(`#storyCommentList-${imageId}`);
let data = {
content: commentInput.val()
}
alert(data.content);
return;
if (data.content === "") {
alert("댓글을 작성해주세요!");
return;
}
let content = `
<div class="sl__item__contents__comment" id="storyCommentItem-2"">
<p>
<b>GilDong :</b>
댓글 샘플입니다.
</p>
<button><i class="fas fa-times"></i></button>
</div>
`;
commentList.prepend(content);
commentInput.val("");
}
// (5) 댓글 삭제
function deleteComment() {
}
console.log(data);
console.log(JSON.stringify(data));
이둘의 차이는 위에 있는 데이터는 js 오브젝트고, 밑에는 통신하기 위해서 JSON데이터로 바껴서 던져진것
// (4) 댓글쓰기
function addComment(imageId) {
let commentInput = $(`#storyCommentInput-${imageId}`);
let commentList = $(`#storyCommentList-${imageId}`);
let data = {
imageId: imageId,
content: commentInput.val()
}
//console.log(data);
//console.log(JSON.stringify(data));
if (data.content === "") {
alert("댓글을 작성해주세요!");
return;
}
$.ajax({
type:"post",
url: "/api/comment",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType:"json"
}).done(res=> {
console.log("성공",res);
}).fail(error => {
console.log("오류",error);
});
let content = `
<div class="sl__item__contents__comment" id="storyCommentItem-2"">
<p>
<b>GilDong :</b>
댓글 샘플입니다.
</p>
<button><i class="fas fa-times"></i></button>
</div>
`;
commentList.prepend(content);
commentInput.val("");
}
// (5) 댓글 삭제
function deleteComment() {
}
지금 우리가 던지는 데이터가 두건이다 imageId와 content를 받을떄 Comment로 받을수 없다.
왜냐하면 iamgeId랑 Content를 Comment오브젝트로 받으면 Image는 오브젝트인데
우리가 받는 값은 int값이기떄문에 받을수가 없다.
그래서 DTO를 하나 만들어야한다 .
DB에 댓글내용과 ,이미지아이디, 유저아이디 이런식으로만 넣지 프라이머리 키는 안넣는다.
이런 정보가 아니라 id, conent, imageId, userId가 다 들어간 완벽한 정보가 필요하다.
그럴라면 어쩔수 없이 save를 해야한다. save하려면 comment객체가 필요하다.
package com.cos.photogramstart.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.cos.photogramstart.domain.comment.Comment;
import com.cos.photogramstart.domain.comment.CommentRepository;
import com.cos.photogramstart.domain.image.Image;
import com.cos.photogramstart.domain.user.User;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class CommentService {
private final CommentRepository commentRepository;
@Transactional
public Comment 댓글쓰기(String content, int imageId, int userId) {
//Tip (객체를 만들떄 id값만 담아서 insert 할 수 있다)
Image image = new Image();
image.setId(imageId);
User user = new User();
user.setId(userId);
Comment comment = new Comment();
comment.setContent(content);
comment.setImage(image);
comment.setUser(user);
return commentRepository.save(comment);
}
@Transactional
public void 댓글삭제() {
}
}
user에 있는 id값만 쏙 빼서 DB에 넣어주면된다.
package com.cos.photogramstart.domain.comment;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import com.cos.photogramstart.domain.image.Image;
import com.cos.photogramstart.domain.likes.Likes;
import com.cos.photogramstart.domain.user.User;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(length =100, nullable = false)
private String content;
@JoinColumn(name ="usrId")
@ManyToOne(fetch = FetchType.EAGER)
private User user;
@JoinColumn(name ="imageId")
@ManyToOne(fetch = FetchType.EAGER)
private Image image;
private LocalDateTime createDate;
@PrePersist
public void createDate() {
this.createDate = LocalDateTime.now();
}
}
코멘트가 리턴될떄 content, userId, imageId, createDate 이렇게 한꺼번에 리턴된다 .
근데 왜 값이 다 null이고 1만 나올까? 내가 값을 1만 넣어놨기 떄문이다. image도 3만 넣어놨다.
내가 만약 리턴을 받을떄 세이브 할떄 아이디 값만 넣어서 세이브 했다.
세이브하고 나면 리턴할때 커멘트는 잘 들고오지만, 이미지객채나 , 유저객체는 아이디값만 넣고 가져오게되는데
만약 리턴받았을떄 유저와 이미지의 완벽한 정보가 필요하면 이렇게 넣으면안된다.
하지만 우리는 content와 id랑 username만 알고있으면된다!
지금 username은 어떻게 해결할수 있을까??
세션값넣으면 위험하고 개인적으로 username이 필요하면 usernmae과 댓글 내용, 삭제해야하니까 댓글 아이디가 필요한데 날짜와 시간은 안필요하다.
그래서 유저 리파지토리를 사용한다
package com.cos.photogramstart.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.cos.photogramstart.domain.comment.Comment;
import com.cos.photogramstart.domain.comment.CommentRepository;
import com.cos.photogramstart.domain.image.Image;
import com.cos.photogramstart.domain.user.User;
import com.cos.photogramstart.domain.user.UserRepository;
import com.cos.photogramstart.handler.ex.CustomApiException;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class CommentService {
private final CommentRepository commentRepository;
private final UserRepository userRepository;
@Transactional
public Comment 댓글쓰기(String content, int imageId, int userId) {
//Tip (객체를 만들떄 id값만 담아서 insert 할 수 있다)
// 대신 return 시에 image객체와 user객체는 id값만 가지고 있는 빈 객체를 리턴받는다.
Image image = new Image();
image.setId(imageId);
User userEntity = userRepository.findById(userId).orElseThrow(()-> {
throw new CustomApiException("유저 아이디를 찾을 수 없습니다.");
});
Comment comment = new Comment();
comment.setContent(content);
comment.setImage(image);
comment.setUser(userEntity);
return commentRepository.save(comment);
}
@Transactional
public void 댓글삭제() {
}
}
'Back-End > Spring Boot' 카테고리의 다른 글
2/21 SpringBoot 유효성 검사 및 자동화 AOP처리 (0) | 2022.02.21 |
---|---|
2/21 SpringBoot 뷰 렌더링 완료하기! (0) | 2022.02.21 |
2/17 SPringBoot 프로필 페이지 유저 사진 변경! (0) | 2022.02.17 |
2/17 SpringBoot 인기 페이지 & 프로필 Likes 카운트 구현 (0) | 2022.02.17 |
2/17 SpringBoot Likes View Rendering (0) | 2022.02.17 |