본문 바로가기
Spring Boot

스프링 부트(Spring Boot) 게시판 - REST API 방식으로 댓글 수정 기능 구현하기 [Thymeleaf, MariaDB, IntelliJ, Gradle, MyBatis]

by 도뎡 2023. 4. 20.
반응형
  • 본 게시판 프로젝트는 단계별(step by step)로 진행되니, 이전 단계를 진행하시는 것을 권장드립니다.
  • DBMS 툴은 DBeaver를 이용하며, DB는 MariaDB를 이용합니다. (MariaDB 설치하기)
  • 화면 처리는 HTML5 기반의 자바 템플릿 엔진인 타임리프(Thymeleaf)를 사용합니다.

이전 글에서는 특정 게시글에 등록된 댓글 리스트(목록)를 출력하는 기능을 구현해 보았습니다. 이번에는 기존에 등록된 댓글을 수정하는 기능을 구현해 볼 건데요. 흔히 모달(Modal)이라고 불리는 레이어 팝업(Layer Popup)을 이용해 보겠습니다.

 

1. 댓글 API 컨트롤러(Controller) - 메서드 추가하기

CommentApiController에 다음의 두 메서드를 추가해 주세요.

    // 댓글 상세정보 조회
    @GetMapping("/posts/{postId}/comments/{id}")
    public CommentResponse findCommentById(@PathVariable final Long postId, @PathVariable final Long id) {
        return commentService.findCommentById(id);
    }


    // 기존 댓글 수정
    @PatchMapping("/posts/{postId}/comments/{id}")
    public CommentResponse updateComment(@PathVariable final Long postId, @PathVariable final Long id, @RequestBody final CommentRequest params) {
        commentService.updateComment(params);
        return commentService.findCommentById(id);
    }

 

메서드 설명
findCommentById REST API 설계 규칙에서 다큐먼트(Document)에 해당되는 기능으로, 특정 게시글(postId)에 등록된 모든 댓글 중 PK(id)에 해당되는 댓글을 조회합니다.

댓글을 수정할 때 사용자에게 기존 댓글 정보를 보여주는 용도로 사용됩니다.
updateComment REST API 설계 규칙에서 다큐먼트(Document)에 해당되는 기능으로, 특정 게시글(postId)에 등록된 모든 댓글 중 PK(id)에 해당되는 댓글을 수정합니다.

댓글 수정이 완료되면 수정된 댓글 정보(객체)를 리턴해 주는데요. saveComment( )와 마찬가지로 @RequestBody를 이용해서 JSON 문자열로 넘어오는 댓글 정보를 CommentRequest 객체의 각 멤버 변수에 매핑(바인딩)합니다.

 

2. 레이어 팝업(Layer Popup) HTML 추가하기

댓글 수정은 "레이어 팝업(Layer Popup)" 또는 "모달(Modal)"로 불리는 팝업으로 처리합니다. 우선 view.html의 콘텐츠(content) 프래그먼트에서 전체 내용을 감싸고 있는 <div class="content"></div> 뒤에 다음의 코드를 추가해 주시면 되는데요. 각 엘리먼트는 자바스크립트 함수를 작성한 후 한 번에 설명드리겠습니다.

    <!--/* 댓글 수정 popup */-->
    <div id="commentUpdatePopup" class="popLayer">
        <h3>댓글 수정</h3>
        <div class="pop_container">
            <table class="tb tb_row tl">
                <colgroup>
                    <col style="width:30%;" /><col style="width:70%;" />
                </colgroup>
                <tbody>
                    <tr>
                        <th scope="row">작성자<span class="es">필수 입력</span></th>
                        <td><input type="text" id="modalWriter" name="modalWriter" placeholder="작성자를 입력해 주세요." /></td>
                    </tr>
                    <tr>
                        <th scope="row">내용<span class="es">필수 입력</span></th>
                        <td><textarea id="modalContent" name="modalContent" cols="90" rows="10" placeholder="수정할 내용을 입력해 주세요."></textarea></td>
                    </tr>
                </tbody>
            </table>
            <p class="btn_set">
                <button type="button" id="commentUpdateBtn" class="btns btn_st2">수정</button>
                <button type="button" class="btns btn_bdr2" onclick="closeCommentUpdatePopup();">취소</button>
            </p>
        </div>
        <button type="button" class="btn_close" onclick="closeCommentUpdatePopup();"><span><i class="far fa-times-circle"></i></span></button>
    </div>

 

3. 레이어 팝업(Layer Popup) 관련 JS 함수 작성하기

view.html의 JS(script) 프래그먼트에 다음의 함수들을 추가해 주세요.

    // 댓글 수정 팝업 open
    function openCommentUpdatePopup(id) {

        const postId = [[ ${post.id} ]];

        $.ajax({
            url : `/posts/${postId}/comments/${id}`,
            type : 'get',
            dataType : 'json',
            async : false,
            success : function (response) {
                document.getElementById('modalWriter').value = response.writer;
                document.getElementById('modalContent').value = response.content;
                document.getElementById('commentUpdateBtn').setAttribute('onclick', `updateComment(${id})`);
                layerPop('commentUpdatePopup');
            },
            error : function (request, status, error) {
                console.log(error)
            }
        })
    }


    // 댓글 수정 팝업 close
    function closeCommentUpdatePopup() {
        document.querySelectorAll('#modalContent, #modalWriter').forEach(element => element.value = '');
        document.getElementById('commentUpdateBtn').removeAttribute('onclick');
        layerPopClose('commentUpdatePopup');
    }

 

함수 설명
openCommentUpdatePopup( ) CommentController의 findCommentById( )를 호출해서 댓글 상세정보를 조회합니다. success( ) 함수의 response는 URI의 id에 해당되는 단일 댓글 객체입니다.

레이어 팝업의 작성자와 내용에 기존 댓글 정보를 보여주고, 수정 버튼에 updateComment( ) 함수를 클릭 이벤트로 바인딩하는데요. 모든 댓글은 PK(id)를 기준으로 UPDATE 되기 때문에, 팝업이 열리는 시점에 수정 버튼에 댓글의 id를 전달해 주어야 합니다. 이는 updateComment( ) 함수를 작성하는 과정에서 다시 설명드리겠습니다.

layerPop( ) 함수는 기존에 common.js에 선언되어 있던 함수로, 화면에 레이어 팝업을 띄워주는 기능을 합니다.
closeCommentUpdatePopup( ) 레이어 팝업의 작성자와 내용을 초기화하고, 수정 버튼에 바인딩된 클릭 이벤트를 제거한 후 팝업을 닫습니다.

layerPopClose( ) 함수도 마찬가지로 기존에 common.js에 선언되어 있던 함수로, 화면에서 레이어 팝업을 닫는 기능을 합니다.

 

4. findAllComment( ) 함수 수정하기

각 댓글의 수정 버튼을 클릭했을 때 레이어 팝업이 오픈될 수 있도록 수정 버튼에 클릭 이벤트를 선언해 주어야 합니다. view.html의 findAllComment( )에서 commentHtml에 그리는 버튼을 다음과 같이 변경해 주세요.

    <p class="func_btns">
        <button type="button" onclick="openCommentUpdatePopup(${row.id});" class="btns"><span class="icons icon_modify">수정</span></button>
        <button type="button" class="btns"><span class="icons icon_del">삭제</span></button>
    </p>

 

5. 댓글 목록의 수정 버튼 클릭해 보기

이제, 상세 페이지에서 댓글 수정 버튼을 클릭해 보면 레이어 팝업에 기존 댓글 정보가 출력됩니다.

레이어 팝업 오픈 결과 - (5번 댓글)

 

다음은 레이어 팝업의 수정 버튼입니다. 댓글 목록에서 수정을 클릭하면 실행되는 openCommentUpdatePopup( ) 함수에 의해 onclick 이벤트로 updateComment( )가 바인딩되며, 뒤에서 해당 함수를 이용해 댓글 정보를 수정합니다.

레이어 팝업 수정 버튼 (팝업 open)

 

레이어 팝업 우측 상단의 X 또는 취소 버튼을 클릭하면 closeCommentUpdatePopup( ) 함수에 의해 onclick 이벤트가 제거됩니다.

레이어 팝업 수정 버튼 (팝업 close)

 

6. updateComment( ) 함수 작성하기

마지막으로 view.html에 레이어 팝업의 수정 버튼을 클릭했을 때 실행되는 updateComment( ) 함수를 작성해 주세요.

    // 댓글 수정
    function updateComment(id) {

        const writer = document.getElementById('modalWriter');
        const content = document.getElementById('modalContent');
        isValid(writer, '작성자');
        isValid(content, '수정할 내용');

        const postId = [[ ${post.id} ]];
        const params = {
            id : id,
            postId : postId,
            content : content.value,
            writer : writer.value
        }

        $.ajax({
            url : `/posts/${postId}/comments/${id}`,
            type : 'patch',
            contentType : 'application/json; charset=utf-8',
            dataType : 'json',
            data : JSON.stringify(params),
            async : false,
            success : function (response) {
                alert('수정되었습니다.');
                closeCommentUpdatePopup();
                findAllComment();
            },
            error : function (request, status, error) {
                console.log(error)
            }
        })
    }

 

로직 해석

saveComment( )와 유사한 기능을 하는 함수입니다. 해당 함수는 파라미터로 댓글의 id를 전달받아 서버로 함께 전송합니다. 댓글 수정이 완료되면 레이어 팝업을 닫은 후 댓글을 다시 조회합니다.

 

7. 댓글 수정해 보기

기존에 등록된 5번 댓글의 작성자와 내용을 수정해 보겠습니다.

5번 댓글 수정 화면 (내용 입력 및 수정)

 

수정 완료 메시지를 닫으면 레이어 팝업이 초기화되고, 수정된 내용이 즉시 댓글에 반영됩니다.

5번 댓글 수정 완료

 

마치며

이렇게 댓글 수정 기능까지 구현이 완료되었습니다. 웹 사이트에서 팝업은 대표적으로 윈도우 팝업(window.open)과 이번에 사용한 레이어 팝업으로 나뉘는데요. 윈도우 팝업은 사이즈 조절이 가능하며 창을 마음대로 이동할 수 있으나, 레이어 팝업은 창 컨트롤이 불가능하다는 특징이 있습니다.

실무에서는 두 가지 팝업 모두를 자주 사용하게 되는데요. 윈도우 팝업은 부모창과 자식창 간의 데이터 전달이 레이어 팝업에 비해 까다롭기 때문에 개인적으로 레이어 팝업 사용을 지향하는 편입니다. 디자인적인 측면에서도 레이어 팝업이 훨씬 깔끔합니다.

이제 댓글 기능 구현도 거의 마무리되어 가고 있습니다. 여기까지 오신다고 고생 많으셨습니다. 다음 글에서는 댓글 삭제 기능을 구현해 보겠습니다.

오늘도 방문해 주셔서 감사드립니다. 좋은 하루 보내세요 :)

Board.zip
0.87MB

 

반응형

댓글