본문 바로가기

Java/Spring

[Spring] 게시판 만들기 #11

What to do?

댓글 작성 기능 구현하기


구현내용

 

  • 댓글 작성 후 제출 버튼 클릭

 

  • 최신 댓글들을 위로 오게 정렬해서 댓글 보여주기


Controller

 

댓글 CRUD

 

  1. Create
    • /comments/write 경로로 post 요청
    • saveComment 메써드
  2. Read
    • ArticleController에서 이미 구현함
  3. Update
    • /comments 경로로 put 요청
    • updateComment 메써드
  4. Delete
    • /comments 경로로 delete 요청
    • deleteComment 메써드

 

CommentController.java

@Controller
@RequestMapping("/comments")
@RequiredArgsConstructor
public class CommentController {
    private final CommentService commentService;

    @PostMapping("/write")
    public String saveComment(WriteCommentRequest writeCommentRequest){
        // TODO : 인증기능 구현 후에 createdBy는 실제 유저명 넣기
        UserAccountDto userAccountDto = UserAccountDto.of("test email", "karma", "test password", "test description", RoleType.USER);
        CommentDto commentDto = WriteCommentRequest.to(writeCommentRequest);
        commentService.saveComment(userAccountDto, commentDto);
        return String.format("redirect:/articles/%s", writeCommentRequest.getArticleId());
    }

    @PutMapping("/{commentId}")
    public String updateComment(@PathVariable Long commentId, UpdateCommentRequest req){
        // TODO : 인증기능 구현 후 자기가 작성한 댓글만 수정할 수 있도록
        commentService.updateComment(commentId, req.getContent());
        return String.format("redirect:/articles/%s", req.getArticleId());
    }

    @PostMapping("/{commentId}")
    public String deleteComment(@PathVariable Long commentId, DeleteCommentRequest req){
        // TODO : 인증기능 구현 후 자기가 작성한 댓글만 삭제할 수 있도록
        commentService.deleteComment(commentId);
        return String.format("redirect:/articles/%s", req.getArticleId());
    }
}

 


Service

 

CommentService.java

@Service
@Transactional
@RequiredArgsConstructor
public class CommentService {
    private final UserAccountRepository userAccountRepository;
    private final ArticleRepository articleRepository;
    private final CommentRepository commentRepository;

    public void saveComment(UserAccountDto userAccountDto,CommentDto commentDto){
        userAccountRepository.findByUsername(userAccountDto.getUsername())
                .orElseThrow(()->{throw new MyException(
                        ErrorCode.USER_NOT_FOUND,
                        String.format("Username [%s] is not founded", userAccountDto.getUsername()));});
        Article article = articleRepository.findById(commentDto.getArticleId()).orElseThrow(()->{
            throw new MyException(
                    ErrorCode.ENTITY_NOT_FOUND,
                    String.format("Article with id [%s] is not founded",  commentDto.getArticleId()));});
        Comment comment = Comment.of(article, commentDto.getContent());
        // Save
        commentRepository.save(comment);
    }

    public void updateComment(Long commentId, String content){
        Comment comment = commentRepository
                .findById(commentId)
                .orElseThrow(()->{throw new MyException(
                        ErrorCode.ENTITY_NOT_FOUND,
                        String.format("Comment with [%s] is not founded", commentId)
                );});
        comment.setContent(content);
        commentRepository.save(comment);
    }

    public void deleteComment(Long commentId){
        commentRepository.deleteById(commentId);
    }
}

 

에러가 날 때 thorws new MyException과 같이 내가 정의한 에러를 던지도록 했다.

(UsernameNotFoundException, EntityNotFoundException 과 같이 이미 정의된 에러를 던지도록 해도 똑같이 동작한다)


HTML

 

resources/articles/detail/index.html

 

  • Service, Controller에서는 댓글 작성/조회/수정/삭제를 구현해놓았지만, View에서는 댓글 작성/조회만 구현해놓았다.
  • CommentController의 saveComment 메써드에서 /comments/write 경로로 post 요청을 보내면 댓글이 작성되도록 만들어 놓음 → form 태그 action="/comments/write" method="post"
<!--댓글쓰기-->
<div class="row mt-3">
  <section id="write-comment-area" name="write-comment-area">
    <form class="row" action="/comments/write" method="post">
      <!--게시글 Id-->
      <input name="articleId" id="article-id" hidden/>
      <div class="col form-floating">
        <!--댓글입력-->
        <textarea class="form-control h-100" placeholder="Leave a comment here"
                  id="floatingTextarea" name="content" style="resize:none;"></textarea>
        <label for="floatingTextarea">Comment</label>
      </div>
      <div class="col-1 align-self-center">
        <button class="btn btn-primary" id="btn-submit" type="submit">Submit</button>
      </div>
    </form>

 

  • 댓글보기
<!--댓글보기-->
<div class="accordion mt-3">
  <div class="accordion-item">
    <h2 class="accordion-header" id="headingOne">
      <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
        See Comments
      </button>
    </h2>
    <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
      <ul id="article-comments" class="row col-7">
        <li class="list-group-item">
          <div>
            <strong>AUTHOR</strong>
            <small><time>2022-01-01</time></small>
            <p>COMMENT</p>
          </div>
        </li>
      </ul>
    </div>
  </div>
</div>

Thymeleaf Template

 

  • 댓글 작성
    • 댓글 저장 시에 게시글 id가 필요해서 Aritcle Controller에서 받은 게시글 id를 주입
<!--Write Comment-->
<attr sel="#write-comment-area">
    <attr sel="#article-id" th:value="${articleId}"/>
</attr>

 

  • 댓글보기
<!--See Comments-->
<attr sel="#article-comments">
    <attr sel="li" th:remove="all-but-first">
        <attr sel="div" th:each="comment : ${comments.comments}">
            <attr sel="strong" th:text="${comment.createdBy}"/>
            <attr sel="small/time" th:datetime="${comment.createdAt}" th:text="${#temporals.format(comment.createdAt, 'yy년 MM월 dd일 hh시 mm분')}"/>
            <attr sel="p" th:text="${comment.content}"/>
        </attr>
    </attr>
</attr>

 

'Java > Spring' 카테고리의 다른 글

[Spring] 길찾기 서비스 #5  (0) 2022.12.11
[Spring] 게시판 만들기 #12  (0) 2022.11.26
[Spring] 게시판 만들기 #10  (0) 2022.11.23
[Spring] 게시판 만들기 #9  (0) 2022.11.23
[Spring] 게시판 만들기 #8  (0) 2022.11.23