[클론 코딩] 네이버 카페 - 댓글 작성

2024. 6. 8. 01:31Project/Naver Cafe

  카페 회원은 네이버 카페 게시글에 댓글을 작성할 수 있다. 이번에는 이 댓글 작성에 대한 기능을 구현하고자 한다. 사용자에게 댓글 작성 양식이 제공될 것이고, 사용자는 양식에 정보를 입력해 댓글 등록 요청을 할 것이다. 그리고 서버는 요청 정보를 통해 댓글 정보를 DB에 저장할 것이고 더불어 게시글의 댓글수 정보를 수정해 DB에 반영할 것이다.


Comment

package CloneCoding.NaverCafe.domain.comment;

@Entity
@Table(name = "COMMENT")
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Comment {

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

    @Column(name = "MENU_ID")
    private Long menuId;

    @Column(name = "PROFILE_IMAGE")
    private String profileImage;

    @Column(name = "ACCOUNT_ID")
    private String accountId;

    @Column(name = "NICKNAME")
    private String nickname;

    @Column(name = "BODY")
    private String body;

    @Column(name = "CREATE_AT")
    private LocalDateTime createAt;

    @Column(name = "UPDATE_AT")
    private LocalDateTime updateAt;

    @Column(name = "REPLY_MAIN")
    @Builder.Default
    private Long replyMain = 0L;

    @Column(name = "REPLY_TARGET")
    @Builder.Default
    private Long replyTarget = 0L;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CAFE_ID")
    private Cafe cafeId;

    public static Comment create(CafeMember cafeMember, Long menuId, RequestWriteComment request) {
        return Comment.builder()
                .menuId(menuId)
                .profileImage(cafeMember.getProfileImage())
                .accountId(cafeMember.getAccountId())
                .nickname(cafeMember.getNickname())
                .body(request.getBody())
                .createAt(LocalDateTime.now())
                .updateAt(LocalDateTime.now())
                .cafeId(cafeMember.getCafeId())
                .build();
    }

}

 

  • create() : Comment 객체를 생성한 후, 객체를 반환

RequestWriteComment

package CloneCoding.NaverCafe.domain.comment.dto;

@Getter
public class RequestWriteComment {

    @NotNull
    private String body;

}

 

  댓글 작성 정보를 전달하는 DTO 클래스


ResponseWriteForm

package CloneCoding.NaverCafe.domain.comment.dto;

import static CloneCoding.NaverCafe.domain.comment.enums.BasicData.DEFAULT_BODY;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResponseWriteForm {

    private String nickname;

    @Builder.Default
    private String body = DEFAULT_BODY.getValue();

}

 

  사용자에게 제공할 댓글 양식에 필요한 정보를 전달하는 DTO


CommentController

package CloneCoding.NaverCafe.domain.comment.controller;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/cafe/{cafe_url}/{normal_id}")
public class CommentController {

    private final CommentService commentService;

    @GetMapping("/comment/form")
    public ResponseWriteForm getCommentForm(@PathVariable("cafe_url") String url,
                                            @PathVariable("normal_id") Long id,
                                            @RequestHeader("Authorization") String token) {
        log.info("댓글 양식 요청");
        return commentService.createForm(url, id, token);
    }

    @PostMapping("/comment")
    public String writeComment(@PathVariable("cafe_url") String url,
                               @PathVariable("normal_id") Long id,
                               @RequestBody @Valid RequestWriteComment request,
                               @RequestHeader("Authorization") String token) {
        log.info("댓글 작성 요청");
        return commentService.createComment(url, id, request, token);
    }

}

 

  • getCommentForm() : 카페 url, 게시글 id, 토큰 정보로 CommentService의 createForm()을 호출하고 결과 값을 반환
  • writeComment() : 카페 url, 게시글 id, 요청 정보, 토큰 정보로 CommentService의 createComment()를 호출하고 결과 메시지를 반환

CommentServiceImpl

package CloneCoding.NaverCafe.domain.comment.service;

import static CloneCoding.NaverCafe.message.SystemMessage.WRITE_COMMENT_COMPLETE;

@Service
@RequiredArgsConstructor
public class CommentServiceImpl implements CommentService {

    private final CommentRepository commentRepository;
    private final CafeRepository cafeRepository;
    private final CafeMemberRepository cafeMemberRepository;
    private final NormalRepository normalRepository;
    private final AesUtil aesUtil;

    @Override
    public ResponseWriteForm createForm(String url, Long id, String token) {

        CafeMember user = checkCafeMember(url, token);

        return ResponseWriteForm.builder()
                .nickname(user.getNickname())
                .build();
    }

    @Transactional
    @Override
    public String createComment(String url, Long id, RequestWriteComment request, String token) {

        CafeMember user = checkCafeMember(url, token);
        Normal article = normalRepository.findByIdWithLock(id)
                .orElseThrow(() -> new NoSuchElementException("게시글 정보를 찾을 수 없습니다."));

        Comment comment = Comment.create(user, article.getId(), request);
        article.addCommentCount();

        commentRepository.save(comment);
        normalRepository.save(article);

        return WRITE_COMMENT_COMPLETE.getMessage();
    }

    private CafeMember checkCafeMember(String url, String token) {
        String accountId = aesUtil.aesDecode(token);
        Cafe findCafe = cafeRepository.findByUrl(url);
        return cafeMemberRepository.findByAccountId(findCafe, accountId);
    }

}

 

  • createForm() : ResponseWriteForm 객체를 생성하고, 생성한 객체를 반환
  • createComment() : Comment 객체(엔티티)를 생성해 저장하고, Normal 엔티티를 수정한 후, 결과 메시지를 반환
  • checkCafeMember() : 카페 url, 토큰 정보로 조회한 CafeMember 객체(엔티티)를 반환

API TEST

API TEST - 댓글 양식 가져오기

 

  사용자에게 제공될 양식에 필요한 정보를 요청한 테스트이다. 사용자의 닉네임과 댓글 본문에 기본적으로 제공될 메시지가 반환된 것을 확인할 수 있다.

 

DB - 댓글 작성 전

 

  댓글 작성전 NORMAL 테이블의 이미지이다. COMMENT_COUNT 속성 값이 '0'인 것을 확인할 수 있다.

 

API TEST - 댓글 작성

 

DB - 댓글 작성 후

 

DB - COMMENT 테이블

 

  댓글 작성을 요청한 테스트이다. 요청에 대한 결과 메시지가 잘 출력된 것을 확인할 수 있고, DB의 NORMAL 테이블을 확인하면 COMMENT_COUNT 속성 값이 '0'에서 '1'로 증가했으며, 또한 COMMENT 테이블에 레코드가 추가된 것을 확인할 수 있다.