티스토리 뷰

댓글 저장 화면 / 댓글 수정 버튼 클릭시 모달(modal)

1. HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ajax Test 5</title>
    <link rel="stylesheet" th:href="@{/static/css/styles.css}">
    <script th:src="@{/static/jq/jquery-3.7.1.min.js}"></script>
    <script th:src="@{/static/js/test5JS.js}"></script>
</head>
<body>
<div class="container">
    <header>
        <h1>[ 임의의 게시판 ]</h1> <!-- 게시판 만들기 자체는 Web5 프로젝트 참고 -->
        <p>게시판 내용</p>
        <h1>[ Ajax Test 5 - 댓글 달기 ]</h1>
    </header>
    <main>
        <div id="content" class="content">
            <!-- AJAX 로드된 데이터가 아래에 표시됩니다. -->
            <form id="inputForm">
                <input type="text" id="name" name="name" placeholder="작성자명을 입력하세요.">
                <input type="text" id="comment" name="comment" placeholder="댓글 내용을 입력하세요.">
                <button type="button" id="inputButton">저장</button>
            </form>
        </div>
        <hr>
        <!-- 댓글 리스트 출력부분 -->
        <table class="commentTable">
            <thead>
            <tr>
                <th style="width: 8%">번호</th>
                <th style="width: 16%">작성자</th>
                <th style="width: 42%">내용</th>
                <th style="width: 17%"></th>
                <th style="width: 17%"></th>
            </tr>
            </thead>
            <tbody id="commentTbody">
            </tbody>
        </table>
        <!-- 모달 부분 -->
        <div class="modalBack" id="modalBackground">
            <div id="modalArea"></div>
        </div>
    </main>
    <hr>
    <form>
        <a href="javascript:history.back();"><button type="button">HOME</button></a>
    </form>
    <footer>
        <p>&copy; 2024.08.14 AJAX Practice</p>
    </footer>
</div>
</body>
</html>

 

2. Javascript

// ready 함수
$(document).ready(function () {
    // 댓글 입력 버튼 클릭 시 commentInput 함수 실행
    $('#inputButton').click(commentInput);

    // 페이지 로딩 시 댓글 목록을 불러와 출력
    list();

    // 댓글 수정 버튼 클릭 이벤트 핸들러
    $(document).on('click', '.editBtn', function () {
        // 수정할 댓글의 고유 번호를 가져옴
        let num = $(this).data('num');
        console.log("수정 요청한 댓글 번호:{}", num);

        // 사용자가 수정 버튼을 클릭하면, 모달 영역을 생성하여 수정 입력을 받음
        let modal = `<div id="modal">
                             <span>${num}</span>번 글 수정하기<br>
                             내용 수정: <input id="reComment" type="text" style="width: 200px;margin-bottom: 10px"><br>
                             <button id="updateButton">수정</button></div>`;
        // 모달 내용을 modalArea에 추가
        $("#modalArea").html(modal);

        // 모달과 배경 영역을 화면에 표시
        $("#modalBackground").css("display", "block");
        $("#modalArea").css("display", "block");

        // 모달에서 수정 버튼 클릭 시 수정 처리
        $(document).on('click', '#updateButton', function () {
            // 수정할 데이터(댓글 번호, 이름, 내용)를 객체로 생성
            let data = {num: num, name: $("#reName").val(), comment: $("#reComment").val()};
            console.log("수정 요청한 정보: ", data);

            // 수정 요청을 서버로 전송
            $.ajax({
                url: 'update',
                type: 'post',
                data: data,
                success: function () {
                    alert('수정 완료');
                    // 수정 성공 시 댓글 목록 갱신
                    list();
                    // 모달과 배경 영역을 화면에서 숨김
                    $("#modalBackground").css("display", "none");
                    $("#modalArea").css("display", "none");
                },
                error: function () {
                    alert('수정 실패');
                }
            });
        });
    });
});

// 댓글 저장
function commentInput() {
    // 이름 또는 댓글 내용이 비어있으면 경고 메시지 출력
    if($('#name').val() == '' || $('#comment').val() == '') {
        alert('이름 혹은 내용을 입력하세요.');
        return;
    }
    // 댓글 저장 요청을 서버로 전송
    $.ajax({
        url : 'input',
        type : 'post',
        data : $('#inputForm').serialize(), // 폼 데이터를 직렬화하여 전송
        success : function () {
            alert('저장 성공');
            // 저장 성공 시 입력 폼 초기화
            $('#name').val('');
            $('#comment').val('');
            // 댓글 목록 갱신
            list();
        },
        error : function () {
            alert('저장 실패');
        }
    });
}

// 댓글 목록을 가져와서 출력
function list() {
    // 댓글 목록을 가져오기 위한 GET 요청
    $.ajax({
        url: 'input', // 서버로부터 객체를 받을 URL
        type: 'get', // HTTP 메서드 타입을 GET으로 설정
        dataType: 'json', // 응답 데이터 타입을 JSON으로 설정
        success: function (dtoList) {
            console.log(dtoList);
            $('#commentTbody').empty(); // 댓글 목록을 비워 초기화
            // 각 댓글 데이터를 HTML로 변환하여 테이블에 추가
            $(dtoList).each(function (index, item) {
                let txt = `<tr>
                            <td>${item.num}</td>
                            <td>${item.name}</td>
                            <td>${item.comment}</td>
                            <td><button class="deleteBtn" data-num="${item.num}">삭제</button></td>
                            <td><button class="editBtn" data-num="${item.num}" data-name="${item.name}"
                             data-comment="${item.comment}">수정</button></td>
                        </tr>`;
                $('#commentTbody').append(txt);
            });
            // 삭제 버튼 클릭 이벤트 핸들러 연결
            $('.deleteBtn').click(deleteBtn);
            // 수정 버튼 클릭 이벤트 핸들러 연결
            $('.editBtn').click(editBtn);
        },
        error: function () {
            alert('댓글 목록 불러오기 실패');
        }
    });
}

// 삭제 이벤트
function deleteBtn() {
    // 삭제할 댓글의 고유 번호를 가져옴
    let deleteNum = $(this).data('num');
    // 댓글 삭제 요청을 서버로 전송
    $.ajax({
        url : 'delete',
        type : 'post',
        data : {num : deleteNum}, // 삭제할 댓글의 번호를 전송
        success : function () {
            alert('삭제 성공');
            // 삭제 성공 시 댓글 목록 갱신
            list();
        },
        error : function () {
            alert('삭제 실패');
        }
    });
}

 

3. Controller

package net.datasa.test_ajax.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.datasa.test_ajax.domain.DTO.CommentDTO;
import net.datasa.test_ajax.service.AjaxTest5Service;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 댓글 관련 Ajax Controller
 */
@RestController // 이 클래스의 모든 메서드는 JSON 형태의 데이터를 반환하는 RESTful 웹 서비스의 엔드포인트로 동작함
@RequiredArgsConstructor // 필수 필드(final 필드)들을 포함한 생성자를 자동으로 생성
@Slf4j // 로깅 기능을 사용할 수 있도록 지원
@RequestMapping("comment") // 이 클래스의 모든 메서드는 "comment" 경로 하위의 URL에 매핑됨
public class AjaxTest5Controller {

    // 서비스 객체 주입, 이 객체를 통해 비즈니스 로직을 처리
    private final AjaxTest5Service ajaxTest5Service;

    /**
     * 댓글 저장을 처리하는 메서드
     * @param commentDTO 저장할 댓글의 정보를 담고 있는 DTO 객체
     */
    @PostMapping("input") // HTTP POST 요청을 처리하며, "comment/input" 경로와 매핑
    public void input(CommentDTO commentDTO) {
        // 전달된 DTO 객체를 로그에 출력하여 디버깅에 사용
        log.debug("AjaxTest5Controller의 input() 메소드로 전달된 객체 : {}", commentDTO);
        // DTO 객체를 서비스로 전달하여 데이터베이스에 저장
        ajaxTest5Service.save(commentDTO);
    }

    /**
     * 저장된 댓글 목록을 가져오는 메서드
     * @return 댓글 DTO 리스트를 반환
     */
    @GetMapping("input") // HTTP GET 요청을 처리하며, "comment/input" 경로와 매핑
    public List<CommentDTO> getCommentDTO() {
        // 서비스로부터 댓글 목록을 가져옴
        List<CommentDTO> dtoList = ajaxTest5Service.list();
        // 댓글 목록을 반환
        return dtoList;
    }

    /**
     * 댓글 삭제를 처리하는 메서드
     * @param num 삭제할 댓글의 고유 번호
     */
    @PostMapping("delete") // HTTP POST 요청을 처리하며, "comment/delete" 경로와 매핑
    public void delete(Integer num) {
        // 전달된 고유 번호를 로그에 출력하여 디버깅에 사용
        log.debug("delete() 메소드로 전달된 객체 : {}", num);
        // 고유 번호를 서비스로 전달하여 데이터베이스에서 해당 댓글을 삭제
        ajaxTest5Service.delete(num);
    }

    /**
     * 댓글 수정을 처리하는 메서드
     * @param commentDTO 수정할 댓글의 정보를 담고 있는 DTO 객체
     */
    @PostMapping("update") // HTTP POST 요청을 처리하며, "comment/update" 경로와 매핑
    public void update(CommentDTO commentDTO) {
        // 전달된 DTO 객체를 로그에 출력하여 디버깅에 사용
        log.debug("update() 메소드로 전달된 객체 : {}", commentDTO);
        // DTO 객체를 서비스로 전달하여 데이터베이스에서 해당 댓글을 수정
        ajaxTest5Service.update(commentDTO);
    }
}

 

4. Service

package net.datasa.test_ajax.service;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import net.datasa.test_ajax.domain.DTO.CommentDTO;
import net.datasa.test_ajax.domain.Entity.CommentEntity;
import net.datasa.test_ajax.repository.CommentRepository;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service // 이 클래스가 서비스 레이어의 컴포넌트임을 명시하며, 비즈니스 로직을 담당
@Transactional // 이 클래스 내의 메서드들이 트랜잭션 단위로 실행됨을 명시
@RequiredArgsConstructor // final로 선언된 필드들을 포함한 생성자를 자동으로 생성
public class AjaxTest5Service {

    // 댓글 데이터를 처리하는 리포지토리 객체 주입
    private final CommentRepository commentRepository;

    /**
     * 댓글 저장
     * @param commentDTO 저장할 댓글 정보가 담긴 DTO 객체
     */
    public void save(CommentDTO commentDTO) {
        // DTO 객체를 엔티티 객체로 변환
        CommentEntity commentEntity = new CommentEntity();
        commentEntity.setName(commentDTO.getName());
        commentEntity.setComment(commentDTO.getComment());

        // 변환된 엔티티 객체를 데이터베이스에 저장
        commentRepository.save(commentEntity);
    }

    /**
     * 댓글 리스트 불러오기
     * @return 모든 댓글 정보를 담고 있는 DTO 리스트 반환
     */
    public List<CommentDTO> list() {
        // 모든 댓글 엔티티를 데이터베이스에서 조회
        List<CommentEntity> entityList = commentRepository.findAll();
        // 조회된 엔티티를 DTO로 변환하여 담을 리스트 생성
        List<CommentDTO> dtoList = new ArrayList<>();

        // 엔티티 리스트를 순회하며 DTO로 변환
        for (CommentEntity entity : entityList) {
            CommentDTO commentDTO = new CommentDTO();
            commentDTO.setNum(entity.getNum());
            commentDTO.setName(entity.getName()); // 엔티티로부터 이름을 가져와 설정
            commentDTO.setComment(entity.getComment()); // 엔티티로부터 댓글 내용을 가져와 설정
            dtoList.add(commentDTO); // 변환된 DTO를 리스트에 추가
        }
        // 모든 댓글 정보를 포함한 DTO 리스트 반환
        return dtoList;
    }

    /**
     * 댓글 삭제
     * @param num 삭제할 댓글의 고유 번호
     */
    public void delete(Integer num) {
        // 주어진 고유 번호를 가진 댓글을 데이터베이스에서 삭제
        commentRepository.deleteById(num);
    }

    /**
     * 댓글 수정
     * @param commentDTO 수정할 댓글 정보가 담긴 DTO 객체
     */
    public void update(CommentDTO commentDTO) {
        // DTO 객체의 고유 번호로 엔티티를 조회, 없으면 예외 발생
        CommentEntity commentEntity = commentRepository.findById(commentDTO.getNum())
                .orElseThrow(() -> new RuntimeException("없는 댓글"));

        // 조회된 엔티티의 댓글 내용을 DTO로부터 가져와 업데이트
        commentEntity.setComment(commentDTO.getComment());
        // 수정된 엔티티를 데이터베이스에 저장
        commentRepository.save(commentEntity);
    }
}

 

5. DTO

package net.datasa.test_ajax.domain.DTO;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommentDTO {
    private Integer num;
    private String name;
    private String comment;


}

 

6. Entity

package net.datasa.test_ajax.domain.Entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 댓글 엔티티
 */
@Data // Lombok 어노테이션으로, getter, setter, toString, equals, hashCode 메서드를 자동으로 생성
@Builder // Lombok 어노테이션으로, 빌더 패턴을 사용할 수 있게 합니다.
@NoArgsConstructor // Lombok 어노테이션으로, 매개변수가 없는 생성자를 자동으로 생성
@AllArgsConstructor // Lombok 어노테이션으로, 모든 필드를 매개변수로 가지는 생성자를 자동으로 생성
@Entity // JPA 어노테이션으로, 이 클래스가 엔티티임을 나타냄
@Table(name = "ajax_comment") // JPA 어노테이션으로, 엔티티와 매핑되는 테이블의 이름을 지정
public class CommentEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer num;

    @Column(name="name", length = 30, nullable = false)
    private String name;

    @Column(name="comment",length = 1000, nullable = false)
    private String comment;
}

 

7. Repository

package net.datasa.test_ajax.repository;

import net.datasa.test_ajax.domain.Entity.CommentEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CommentRepository extends JpaRepository<CommentEntity, Integer> {
}

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함