728x90
320x100
📌 Comment Entity 구현
package yerong.InstagramCloneCoding.domain.comment;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.*;
import lombok.*;
import yerong.InstagramCloneCoding.domain.BaseTimeEntity;
import yerong.InstagramCloneCoding.domain.image.Image;
import yerong.InstagramCloneCoding.domain.user.User;
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Builder
@Entity
public class Comment extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "comment_id")
private Long id;
@Column(length = 100, nullable = false)
private String content;
@JsonIgnoreProperties("images")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "image_id")
private Image image;
}
- User와 Image와 연관관계 설정해줌
📌 CommentRepository 구현
package yerong.InstagramCloneCoding.repository.comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import yerong.InstagramCloneCoding.domain.comment.Comment;
public interface CommentRepository extends JpaRepository<Comment, Long> {
}
📌 Image 와 연관관계 설정
package yerong.InstagramCloneCoding.domain.image;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.*;
import lombok.*;
import yerong.InstagramCloneCoding.domain.BaseTimeEntity;
import yerong.InstagramCloneCoding.domain.comment.Comment;
import yerong.InstagramCloneCoding.domain.likes.Likes;
import yerong.InstagramCloneCoding.domain.user.User;
import java.util.ArrayList;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Builder
@Entity
public class Image extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "image_id")
private Long id;
private String caption;
private String postImageUrl;
@JsonIgnoreProperties({"images"}) //user에 있는 images는 무시
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
//좋아요
@JsonIgnoreProperties({"image"})
@OneToMany(mappedBy = "image")
private List<Likes> likes = new ArrayList<>();
@Transient
private int likeCount;
@OrderBy("id DESC ")
@JsonIgnoreProperties({"image"})
@OneToMany(mappedBy = "image")
private List<Comment> commentList;
public void setLikeCount(int count) {
this.likeCount = count;
}
}
- comment와 연관관계 설정
- comment에 들어가면 image가 또 있으므로 무한참초를 막기 위해 JsonIgnoreProperties 설정을 해줌
- OrderBy("id DESC") 로 id 순으로 정렬
📌 CommentReqDto 구현
package yerong.InstagramCloneCoding.web.dto.comment;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.*;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CommentReqDto {
private Long imageId;
@NotBlank
private String content;
}
- REQUEST DTO
📌 CommentResDto 구현
package yerong.InstagramCloneCoding.web.dto.comment;
import lombok.*;
@Builder
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CommentResDto {
private Long id;
private String content;
private String username;
private Long userId;
}
- RESPONSE DTO
📌 CommentApiController 구현
package yerong.InstagramCloneCoding.web.api;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import yerong.InstagramCloneCoding.config.auth.PrincipalDetails;
import yerong.InstagramCloneCoding.handler.exception.CustomValidationException;
import yerong.InstagramCloneCoding.service.CommentService;
import yerong.InstagramCloneCoding.web.dto.CMRespDto;
import yerong.InstagramCloneCoding.web.dto.comment.CommentReqDto;
import yerong.InstagramCloneCoding.web.dto.comment.CommentResDto;
import java.util.HashMap;
import java.util.Map;
@RequiredArgsConstructor
@RestController
@Slf4j
public class CommentApiController {
private final CommentService commentService;
@PostMapping("/api/comment")
public ResponseEntity<CMRespDto<?>> commentWrite(
@Valid @RequestBody CommentReqDto commentDto,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails){
if(bindingResult.hasErrors()){
Map<String, String> errorMap = new HashMap<>();
for(FieldError error : bindingResult.getFieldErrors()){
errorMap.put(error.getField(), error.getDefaultMessage());
log.info(error.getDefaultMessage());
}
throw new CustomValidationException("유효성 검사 실패", errorMap);
}
else {
CommentResDto commentResDto = commentService.commentWrite(commentDto, principalDetails.getUser().getId());
return new ResponseEntity<CMRespDto<?>>(new CMRespDto<>(1, "댓글 작성 성공", commentResDto), HttpStatus.CREATED);
}
}
@DeleteMapping("/api/comment/{id}")
public ResponseEntity<CMRespDto<?>> commentDelete(
@PathVariable Long id
){
log.info("=====id : " + id + "-======");
commentService.commentDelete(id);
return new ResponseEntity<CMRespDto<?>>(new CMRespDto<>(1, "댓글 삭제 성공", null), HttpStatus.OK);
}
}
- 댓글을 쓰고 지우는 Controller 설정
- @Valid를 통해 DTO에 설정해둔 유효성 검사를 해준다.
📌 ImageDto에 CommentList 추가
package yerong.InstagramCloneCoding.web.dto.image;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import yerong.InstagramCloneCoding.domain.comment.Comment;
import yerong.InstagramCloneCoding.domain.user.User;
import yerong.InstagramCloneCoding.web.dto.comment.CommentResDto;
import java.util.List;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class ImageDto {
private Long id;
private String caption;
private String postImageUrl;
private Long userId;
private String username;
private String profileImageUrl;
private boolean likeState;
private int likeCount;
private List<CommentResDto> commentList;
}
- ImageDto에도 CommentList 추가해줌
📌 CommentService 구현
package yerong.InstagramCloneCoding.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yerong.InstagramCloneCoding.domain.comment.Comment;
import yerong.InstagramCloneCoding.domain.image.Image;
import yerong.InstagramCloneCoding.domain.user.User;
import yerong.InstagramCloneCoding.handler.exception.CustomApiException;
import yerong.InstagramCloneCoding.handler.exception.CustomException;
import yerong.InstagramCloneCoding.repository.comment.CommentRepository;
import yerong.InstagramCloneCoding.repository.image.ImageRepository;
import yerong.InstagramCloneCoding.repository.user.UserRepository;
import yerong.InstagramCloneCoding.service.CommentService;
import yerong.InstagramCloneCoding.web.dto.comment.CommentReqDto;
import yerong.InstagramCloneCoding.web.dto.comment.CommentResDto;
@Service
@RequiredArgsConstructor
@Slf4j
public class CommentServiceImpl implements CommentService {
private final CommentRepository commentRepository;
private final UserRepository userRepository;
private final ImageRepository imageRepository;
@Transactional
@Override
public CommentResDto commentWrite(CommentReqDto requestDto, Long principalid){
User user = userRepository.findById(principalid).orElseThrow(() -> new CustomException("해당 User를 찾을 수 없습니다."));
Image image = imageRepository.findById(requestDto.getImageId()).orElseThrow(() -> new CustomException("해당 이미지를 찾을 수 없습니다."));
Comment comment = Comment.builder()
.content(requestDto.getContent())
.user(user)
.image(image)
.build();
commentRepository.save(comment);
return CommentResDto.builder()
.id(comment.getId())
.content(comment.getContent())
.username(comment.getUser().getUsername())
.build();
}
@Transactional
@Override
public void commentDelete(Long commentId){
try {
Comment comment = commentRepository.findById(commentId).orElseThrow(() -> new CustomException("해당 댓글을 찾을 수 없습니다."));
commentRepository.delete(comment);
}catch (Exception e){
throw new CustomApiException(e.getMessage());
}
}
}
📌 ImageService 에 Comment 저장하는 코드 추가
@Transactional(readOnly = true)
@Override
public Page<ImageDto> imageStory(Long principalId, Pageable pageable){
Page<Image> images = imageRepository.mStory(principalId, pageable);
return images.map(image -> {
boolean likeState = false;
for(Likes like : image.getLikes()) {
if(like.getUser().getId() == principalId) {
likeState = true;
break;
}
}
List<CommentResDto> commentResDtoList = image.getCommentList().stream().map(comment -> {
return CommentResDto.builder()
.id(comment.getId())
.content(comment.getContent())
.username(comment.getUser().getUsername())
.userId(comment.getUser().getId())
.build();
}).collect(Collectors.toList());
return ImageDto.builder()
.id(image.getId())
.caption(image.getCaption())
.postImageUrl(image.getPostImageUrl())
.userId(image.getUser().getId())
.username(image.getUser().getUsername())
.profileImageUrl(image.getUser().getProfileImageUrl())
.likeState(likeState)
.likeCount(image.getLikes().size())
.commentList(commentResDtoList)
.build();
});
}
댓글 구현까지 끝!!
PREV
NEXT
728x90
반응형
'프로젝트 > 인스타그램 클론 코딩' 카테고리의 다른 글
[인스타그램 클론 코딩][Spring boot] 13. 페이스북 소셜 로그인 구현 (0) | 2024.03.02 |
---|---|
[인스타그램 클론 코딩][Spring boot] 12. AOP 처리 (0) | 2024.03.01 |
[인스타그램 클론 코딩][Spring boot] 10. 좋아요 및 인기 페이지 구현 (0) | 2024.02.23 |
[인스타그램 클론 코딩][Spring boot] 9. 스토리(메인) 페이지 (0) | 2024.02.22 |
[인스타그램 클론 코딩][Spring boot] 8. 구독 정보 뷰 렌더링 (0) | 2024.02.21 |