자율학습단 스프링부트 4주차

하파타카·2023년 9월 19일
0

16일차

웹 페이지에서 댓글 목록 보기

view 수정

우선 show.mustache 화면의 맨 밑에 댓글에 대한 부분을 만들어 붙임.
댓글 영역에 대한 div를 _comment.mustache파일로 잡은 후 해당 파일내에 댓글 목록을 출력하는 화면파일과 새 댓글을 작성하는 화면파일을 차례로 가져오도록 만듦.

- _comments.mustache -

<div>
    <!--  댓글 목록 보기  -->
    {{>comments/_list}}
    <!--  새 댓글 작성하기  -->
    {{>comments/_new}}
</div>

- _list.mustache -

<div id="comments-list">
    {{#commentDtos}}
        <div class="card m-2" id="comments-{{id}}">
            <div class="card-header">
                {{nickname}}
            </div>
            <div class="card-body">
                {{body}}
            </div>
        </div>
    {{/commentDtos}}
</div>

- _new.mustache -

<div class="card m-2" id="comments-new">
    <div class="card-body">
        <!--  댓글작성 폼  -->
        <form>
            <div class="m-3">
                <label class="form-label">닉네임</label>
                <input type="text" class="form-control" id="new-comment-nickname">
            </div>
            <div class="m-3">
                <label class="form-label">댓글 내용</label>
                <textarea type="text" class="form-control" rows="3" id="new-comment-body"></textarea>
            </div>
            {{#article}}
                <input type="hidden" id="new-comment-article-id" value="{{id}}">
            {{/article}}
            <button type="button" class="btn btn-primary" id="comment-create-btn">댓글 작성</button>
        </form>
    </div>
</div>

controller 수정

ArticleController에서 @GetMapping("/articles/{id}")으로 단일 게시글을 조회하는 show메서드를 실행 할 때 댓글도 불러오도록 수정한다.

- ArticleController -

@GetMapping("/articles/{id}")
public String show(@PathVariable Long id, Model m) {
    log.info("id = " + id);
    // 1. DB에서 데이터 조회해 가져오기
    Optional<Article> articleEntity = articleRepository.findById(id);
    List<CommentDto> commentDtos = commentService.comments(id);
    // 2. model에 데이터 등록하기
    m.addAttribute("article", articleEntity.get());
    m.addAttribute("commentDtos", commentDtos);
    // 3. 뷰 페이지 반환하기
    return "articles/show";
}

17일차

웹 페이지에서 댓글 등록하기

댓글 입력

- _new.mustache -
script 추가.

<script>
{
    // 댓글 생성 버튼 변수화
    const commentCreateBtn = document.querySelector("#comment-create-btn");
    // 댓글 클릭 이벤트 감지
    commentCreateBtn.addEventListener("click", function() {
        // 새 댓글 객체 생성
        const comment = {
            // 새 댓글의 닉네임
            nickname: document.querySelector("#new-comment-nickname").value,
            // 새 댓글의 본문
            body: document.querySelector("#new-comment-body").value,
            // 부모 게시글의 id
            article_id: document.querySelector("#new-comment-article-id").value
        };
        // 댓글 객체 출력
        console.log(comment);
        // fecth() - 비동기 통신을 위한 api
        const url = "/api/articles/" + comment.article_id + "/comments";
        fetch(url, {
            method: "POST",
            headers: {
                "Content-Type" : "application/json"
            },
            body: JSON.stringify(comment)   // comment 객체를 JSON 문자열로 변환해 전송
        }).then(response => {   // 응답을 받아 처리하는 구문
            // HTTP 응답 코드에 따른 메시지 출력
            const msg = (response.ok) ? "댓글이 등록되었습니다." : "댓글 등록에 실패했습니다.";
            alert(msg);
            // 현재 페이지 새로고침
            window.location.reload();
        });
    });
}
</script>



현재는 작성완료시 화면을 새로고침하여 재조회하도록 되어있음.
Ajax를 이용해 댓글란만 새로고침할 수 있도록 수정해야 할 것 같음.

Javascript로 REST API 호출 및 응답 처리하기

기본형태

fetch('API_주소', {
    method: "POST",				// 요청 메서드
    headers: {					// 헤더 정보
        "Content-Type" : "application/json"
    },
    body: JSON.stringify(객체)   // 전송 데이터
}).then(response => {   			// 응답을 받아 처리하는 구문
  	// 응답 처리문
});

에러

dto 객체에 article_id값이 들어오질 않아서(nickname, body값은 잘 들어오는데 article_id는 null로 들어옴) 한참동안 원인찾음.
알고보니 dto의 필드명과 Javascript에서 설정한 id값이 달라서 생긴 문제였음.

셀프체크

<body>
<h1>Hello, <span id="target">World!</span></h1>
<input type="text" placeholder="스프링 부트" />
<button type="button">전송</button>
</body>
<script>
const h1 = document.querySelector("#target");
const btn = document.querySelector("button");
btn.addEventListener("click", function () {
    const inputText = document.querySelector("input").value;
    console.log("버튼 클릭!");
    console.log(inputText);
    if (inputText == "스프링 부트") {
    h1.innerText = "스프링 부트!";
    }
});
</script>



input란에 '스프링 부트'입력 후 전송버튼 클릭 시 h1객체의 텍스트가 변경됨.

18일차

웹 페이지에서 댓글 수정하기


수정 버튼을 클릭하면 모달창을 뜨게 만들어 모달창에서 수정작업 후 등록하도로 작성.

- _list.mustache -

<div id="comments-list">
    {{#commentDtos}}
        <div class="card m-2" id="comments-{{id}}">
            <div class="card-header">
                {{nickname}}
                <!-- Button trigger modal -->
                <button type="button" class="btn btn-sm btn-outline-primary"
                        data-bs-toggle="modal" data-bs-target="#comment-edit-modal"
                        data-bs-id="{{id}}"
                        data-bs-nickname="{{nickname}}"
                        data-bs-body="{{body}}"
                        data-bs-article-id="{{article_id}}">
                    수정
                </button>
                <button type="button"
                        class="btn btn-sm btn-outline-danger comment-delete-btn"
                        data-comment-id="{{id}}">삭제</button>
            </div>
            <div class="card-body">
                {{body}}
            </div>
        </div>
    {{/commentDtos}}
</div>

<!-- Modal -->
<div class="modal fade" id="comment-edit-modal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">댓글 수정</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <!--  댓글작성 폼  -->
                <form>
                    <div class="m-3">
                        <label class="form-label">닉네임</label>
                        <input type="text" class="form-control" id="edit-comment-nickname">
                    </div>
                    <div class="m-3">
                        <label class="form-label">댓글 내용</label>
                        <textarea type="text" class="form-control" rows="3"
                                  id="edit-comment-body"></textarea>
                    </div>
                    <!-- 히든 인풋 -->
                    <input type="hidden" id="edit-comment-id">
                    <input type="hidden" id="edit-comment-article-id">
                    <button type="button" class="btn btn-primary" id="comment-update-btn">수정 완료</button>
                </form>
            </div>
        </div>
    </div>
</div>

- _list.mustache -

<script>
    {
        // 모달요소 선택
        const commentEditModal = document.querySelector("#comment-edit-modal");
        // 모달 이벤트 감지
        commentEditModal.addEventListener("show.bs.modal", function(event) {
            // 1. 트리거 버튼 선택
            const triggerBtn = event.relatedTarget;
            // 2. 데이터 가져오기
            const id = triggerBtn.getAttribute("data-bs-id");
            const nickname = triggerBtn.getAttribute("data-bs-nickname");
            const body = triggerBtn.getAttribute("data-bs-body");
            const article_id = triggerBtn.getAttribute("data-bs-article-id");
            // 3. 수정 폼에 데이터 반영
            document.querySelector("#edit-comment-id").value = id;
            document.querySelector("#edit-comment-nickname").value = nickname;
            document.querySelector("#edit-comment-body").value = body;
            document.querySelector("#edit-comment-article-id").value = article_id;
        })
    }
    {
        // 수정 완료 버튼 선택
        const commentUpdateBtn = document.querySelector("#comment-update-btn");
        // 클릭 이벤트 처리
        commentUpdateBtn.addEventListener("click", function(){
            // 수정 댓글 객체 생성
            const comment = {
                id: document.querySelector("#edit-comment-id").value,
                nickname: document.querySelector("#edit-comment-nickname").value,
                body: document.querySelector("#edit-comment-body").value,
                article_id: document.querySelector("#edit-comment-article-id").value
            }
            console.log(comment);
            // 수정 REST API 호출
            const url = "/api/comments/" + comment.id;
            fetch(url, {
                method: "PATCH",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify(comment)
            }).then(response => {   // 응답을 받아 처리하는 구문
            // HTTP 응답 코드에 따른 메시지 출력
            const msg = (response.ok) ? "댓글이 수정되었습니다." : "댓글 수정에 실패했습니다.";
            alert(msg);
            // 현재 페이지 새로고침
            window.location.reload();
        });
        })
    }
</script>

방식은 등록과 유사함.
수정할 댓글의 '수정'버튼을 클릭하면 모달창에 해당 댓글의 id에 대한 데이터를 가져와 보여주고 모달창에서 댓글을 수정 후 수정 완료버튼을 클릭하면 patch로 api전송을 하도록 함.

19일차

웹 페이지에서 댓글 삭제하기

- _list.mustache -

<script>
// 덧글 삭제
{
    // 삭제 버튼 선택
    const commentDeleteBtns = document.querySelectorAll(".comment-delete-btn");

// 삭제 버튼 이벤트 처리
// commentDeleteBtn.addEventListener("click", function() {
//    console.log("삭제 버튼이 클릭됐습니다..!");
// });
    commentDeleteBtns.forEach(btn => {
        btn.addEventListener("click", (event) => {
            // 이벤트 발생 요소 선택
            const commentDeleteBtn = event.target;
            // 삭제 댓글 id 가져오기
            const commentId = commentDeleteBtn.getAttribute("data-comment-id");
            console.log(`삭제 버튼 클릭: ${commentId}번 댓글`);
            // 삭제 REST API 호출
            const url = `/api/comments/${commentId}`;
            fetch(url, {
                method: "DELETE"
            }).then(response => {
                // 댓글 삭제 실패처리
                if (!response.ok) {
                    alert("댓글 삭제 실패...");
                    return;
                }
                // 삭제 성공 시 댓글을 화면에서 지우고 메시지 창 띄우기
                const target = document.querySelector(`#comments-${commentId}`);
                target.remove();
                const msg = `${commentId}번 댓글을 삭제했습니다`;
                alert(msg);
                // 현재 페이지 새로고침
                window.location.reload();
            })
        })
    })
}
</script>

이벤트 발생 요소 선택 부분에서 자꾸 해당 컴포넌트를 못가져오길래 한참 삽질했더니 event.targetevent.terget으로 오타낸게 원인이었다.
오타를 항상 주의하자...

profile
천 리 길도 가나다라부터

0개의 댓글