본문 바로가기

항해99

23.10.07 항해 99 16기 실전 프로젝트 4일차

오늘 공부한 것

* 실전 프로젝트 대댓글기능 구현

 

오늘은 대댓글 기능을 구현하기로했다

 

처음 해보는 기능이어서 구글링을 해보니 나오는건QueryDSL을 이용하여 구한하는것만 나오더라... 그래서 이 기술을 써볼까 아는것 중에 해볼까 고민을 많이하다가

 

일단은 Comments에다가 Replies를 List 형태로 넣어보기로 하고 코드를 구현했다

 

아직 테스트를 하지못했는데 팀원분께서 작성하신 Post 가 완료되었으니내일은 간단히 테스트를 해봐야겠다

 

1. Controller

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class RepliesController {
    private final RepliesService repliesService;

    // 대댓글 생성
    @PostMapping("/post/{postId}/comments/{commentId}/replies")
    public ResponseEntity<RepliesResponseDto> repliesCreate(@PathVariable("postId") Long postId,
                                                            @PathVariable("commentId") Long commentId,
                                                            @RequestBody RepliesRequestDto requestDto,
                                                            @AuthenticationPrincipal UserDetailsImpl userDetails) {
        return ResponseEntity.ok(repliesService.repliesCreate(postId, commentId, requestDto, userDetails.getUsers()));
    }

    // 대댓글 조회
    @GetMapping("/post/{postId}/comments/{commentId}/replies")
    public ResponseEntity<List<RepliesResponseDto>> repliesList(@PathVariable("postId") Long postId,
                                                                 @PathVariable("commentId") Long commentId) {
        return ResponseEntity.ok(repliesService.repliesList(postId, commentId));
    }

    // 대댓글 수정
    @PutMapping("/post/{postId}/comments/{commentId}/replies/{repliesId}")
    public ResponseEntity<RepliesResponseDto> repliesUpdate(@PathVariable("postId") Long postId,
                                                             @PathVariable("commentId") Long commentId,
                                                             @PathVariable("repliesId") Long repliesId,
                                                             @RequestBody RepliesRequestDto request,
                                                             @RequestBody PostsRequestDto requestDto,
                                                             @AuthenticationPrincipal UserDetailsImpl userDetails) {
        return ResponseEntity.ok(repliesService.repliesUpdate(postId, commentId, repliesId, request, requestDto, userDetails.getUsers()));
    }

    // 대댓글 삭제
    @DeleteMapping("/post/{postId}/comments/{commentId}/replies/{repliesId}")
    public ResponseEntity<MessageResponseDto> repliesDelete(@PathVariable("postId") Long postId,
                                                            @PathVariable("commentId") Long commentId,
                                                            @PathVariable("repliesId") Long repliesId,
                                                            @AuthenticationPrincipal UserDetailsImpl userDetails) {
        return ResponseEntity.ok(repliesService.repliesDelete(postId, commentId, repliesId, userDetails.getUsers()));
    }
}

 

2. Entity

@Entity
@Getter
@NoArgsConstructor
@Table(name = "replies")
public class Replies extends Timestamped {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name ="replies_id")
    private  Long id;

    @Column(nullable = false, unique = true)
    private String nickname;

    @Column(nullable = false, length = 500)
    private String contents;

    @ManyToOne
    @JoinColumn(name = "comments_id")
    private Comments comments;

    public Replies(RepliesRequestDto requestDto) {
        this.nickname = requestDto.getNickname();
        this.contents = requestDto.getContents();
    }

    public void update(RepliesRequestDto requestDto) {
        this.nickname = requestDto.getNickname();
        this.contents = requestDto.getContents();
    }

    public void setComments(Comments comments) {
        this.comments = comments;
    }
}

 

3. Dto

@Getter
public class RepliesRequestDto {
    private String nickname;
    private String contents;
}
@Getter
public class RepliesResponseDto {
    private Long id;
    private String contents;
    private String nickname;
    private LocalDateTime createAt;
    private LocalDateTime modifiedAt;

    public RepliesResponseDto(Replies replies) {
        this.id = replies.getId();
        this.contents = replies.getContents();
        this.nickname = replies.getNickname();
        this.createAt = replies.getCreatedAt();
        this.modifiedAt = replies.getModifiedAt();
    }
}

 

4. Repository

public interface RepliesRepository extends JpaRepository<Replies, Long> {
    List<Replies> findByCommentIdAndPostIdOrderByCreatedAtDesc(Long commentId, Long postId);
}

 

5. Service

@Service
@RequiredArgsConstructor
public class RepliesService {
    private final RepliesRepository repliesRepository;
    private final CommentsRepository commentsRepository;
    private final PostsRepository postsRepository;


    // 대댓글 생성
    public RepliesResponseDto repliesCreate(Long postId,
                                            Long commentId,
                                            RepliesRequestDto requestDto,
                                            Users users) {

        Posts posts = postsRepository.findById(postId).orElseThrow(
                () -> new CustomException(ErrorCode.POST_NOT_EXIST)); // 존재하지 않는 게시글입니다

        Comments comments = commentsRepository.findById(commentId).orElseThrow(
                () -> new CustomException(ErrorCode.POST_NOT_EXIST)); // 존재하지 않는 게시글입니다

        Replies replies = new Replies(requestDto);
        comments.addReplies(replies);
        posts.addComments(comments);

        MessageResponseDto messageResponseDto = new MessageResponseDto(
                "대댓글을 작성하였습니다", 200
        );

        return new RepliesResponseDto(repliesRepository.save(replies));
    }

    // 대댓글 조회
    public List<RepliesResponseDto> repliesList(Long postId,
                                                 Long commentId) {
        return repliesRepository.findByCommentIdAndPostIdOrderByCreatedAtDesc(commentId,postId).stream().map(RepliesResponseDto::new).toList();
    }

    @Transactional
    // 대댓글 수정
    public RepliesResponseDto repliesUpdate(Long postId,
                                             Long commentId,
                                             Long repliesId,
                                             RepliesRequestDto request,
                                             PostsRequestDto requestDto,
                                             Users users) {
        Posts posts = postsRepository.findById(postId).orElseThrow(
                () -> new CustomException(ErrorCode.POST_NOT_EXIST)); // 존재하지 않는 게시글입니다

        Comments comments = commentsRepository.findById(commentId).orElseThrow(
                () -> new CustomException(ErrorCode.POST_NOT_EXIST)); // 존재하지 않는 게시글입니다

        Replies replies = findById(repliesId);
        if (users.getUserRole() == UserRoleEnum.ADMIN) {
            replies.update(request);
            posts.update(requestDto);
            MessageResponseDto messageResponseDto = new MessageResponseDto(
                    "대댓글을 수정하였습니다", 200
            );
            return new RepliesResponseDto(replies);
        } else {
            if (users.getNickName().equals(comments.getNickname())) {
                replies.update(request);
                MessageResponseDto messageResponseDto = new MessageResponseDto(
                        "대댓글을 수정하였습니다", 200
                );
                return new RepliesResponseDto(replies);
            } else {
                throw new CustomException(ErrorCode.NOT_ALLOWED); // 권한이 없습니다
            }
        }
    }

    // 대댓글 삭제
    public MessageResponseDto repliesDelete(Long postId,
                                            Long commentId,
                                            Long repliesId,
                                            Users users) {
        Posts posts = postsRepository.findById(postId).orElseThrow(
                () -> new CustomException(ErrorCode.POST_NOT_EXIST)); // 존재하지 않는 게시글입니다

        Comments comments = commentsRepository.findById(commentId).orElseThrow(
                () -> new CustomException(ErrorCode.POST_NOT_EXIST)); // 존재하지 않는 게시글입니다

        Replies replies = findById(repliesId);
        if (users.getUserRole() == UserRoleEnum.ADMIN) {
            repliesRepository.delete(replies);
            return new MessageResponseDto("대댓글을 삭제하였습니다", 200);
        } else {
            if (users.getNickName().equals(comments.getNickname())) {
                repliesRepository.delete(replies);
                MessageResponseDto messageResponseDto = new MessageResponseDto(
                        "대댓글을 삭제하였습니다", 200
                );
                return new MessageResponseDto("대댓글을 삭제하였습니다", 200);
            } else {
                throw new CustomException(ErrorCode.NOT_ALLOWED); // 권한이 없습니다
            }
        }
    }

    private Replies findById(Long id) {
        return repliesRepository.findById(id).orElseThrow(
                () -> new NullPointerException("유효하지 않은 댓글입니다")
        );
    }
}