본문 바로가기
프로젝트/게시판

[SpringBoot] 게시판 11. 댓글 기능 - 비동기 구현

by qkzkdo 2023. 8. 13.
728x90

구현 순서

1. board-detail.html 

2. reply.html

3. BoardController

4. BoardService

5. BoardServiceProcess

6. BoardMapper

7. board-mapper.xml

8. 댓글 구현 화면

 

 

1. board-detail.html

게시글 상세페이지에 댓글 작성과 조회를 할 영역을 만들어준다.

<div id="reply-area">
    <form id="form-reply">
        <p>
            <input type="text" name="writer" placeholder="작성자">
        </p>
        <p>
            <input type="text" name="content" placeholder="댓글을 입력하세요">
        </p>
        <button type="button" id="btnsave-reply">등록</button>
    </form>
    <hr>
    <div id="reply">

    </div>
</div>

 

 

1-2. board-detail <head>에 자바스크립트 코드 추가

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script type="text/javascript">
    $(function(){
        $("#btnsave-reply").click(btnsaveReplyClicked);
        replyList(1);
    });

    function btnsaveReplyClicked(){
        var stringFormData=$("#form-reply").serialize(); //작성자, 내용
        var boardNo=$("#detail-board-no").text().trim();
        console.log(boardNo);
        console.log(stringFormData);
        $.ajax({
            url:`/boards/${boardNo}/replies`,
            type:"post",
            data: stringFormData,
            success: function(result){
                if(result){
                    replyList(1);
                }
            }
        });
    }

    //댓글갖고오기 요청
    function replyList(pageNo){
        var boardNo=$("#detail-board-no").text().trim();

        $.ajax({
            url:`/boards/${boardNo}/replies`,
            data:{page: pageNo},
            success:function(resultHTML){
                if(pageNo==1)
                    $("#reply").html(resultHTML);
                else{
                    $("#reply>ol").remove();
                    $("#reply").append(resultHTML);
                }
            }
        });
    }
</script>
  • <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    jQuery 라이브러리를 웹 페이지에 로드하는 스크립트 태그
  • function btnsaveReplyClicked(): 댓글 작성자와 내용을 form 데이터로 받아와서 AJAX 요청을 통해 서버로 전송하고, 그 결과에 따라 댓글 목록을 갱신
  • var stringFormData=$("#form-reply").serialize(); : id가 "form-reply"인 폼의 데이터를 시리얼라이즈하여 문자열 형태로 가져온다. 이는 작성자와 내용을 서버로 전송할 데이터 형식으로 만든다.
  • var boardNo=$("#detail-board-no").text().trim(); : id가 "detail-board-no"인 요소의 텍스트 값을 가져와서 공백을 제거한 후 변수 boardNo에 저장
  • if(result) { replyList(1); } : 서버에서 반환된 result 값이 참일 경우, 댓글 목록을 갱신하기 위해 replyList 함수를 호출
  • if(pageNo==1): 만약 현재 페이지 번호가 1이면,
    $("#reply").html(resultHTML); : id가 "reply"인 요소의 내용을 resultHTML로 변경한다.. 즉, 첫 페이지일 때는 새로운 댓글 리스트로 대체.
  • else: 그렇지 않으면 (첫 페이지가 아닌 경우),
    $("#reply>ol").remove(); : id가 "reply"인 요소의 자식 중 ol 태그를 삭제한다. 즉, 기존의 댓글 리스트를 제거.
    $("#reply").append(resultHTML); : id가 "reply"인 요소에 resultHTML을 추가한다. 기존 댓글 리스트를 삭제한 후에 새로운 댓글 리스트가 추가된다.

 

 

*시리얼라이즈(serialization)란 데이터를 일렬로 나열하여 다른 프로그램 또는 시스템에서 쉽게 읽고 사용할 수 있는 형식으로 변환하는 과정을 말한다. 웹 개발에서는 주로 객체나 데이터를 웹 요청 또는 응답의 형태로 변환하기 위해 사용된다.


예를 들어, HTML 폼의 입력 필드들의 값을 서버로 보낼 때, 이 값을 일렬로 나열하여 URL 매개변수나 HTTP 요청 본문의 데이터로 변환하는 것을 시리얼라이즈라고 할 수 있다.

 

 

2. reply.html

조회된 댓글 목록들을 보여줄 html 작성

<!DOCTYPE html>
<html xmlns:th="//www.thymeleaf.org">
<head>
    <style type="text/css">
        li{
            list-style: none;
            margin-right: 20px;			
        }
        ul{
            display: flex;
        }
    </style>
</head>
 
<ul th:each="reply:${list}">
    <li th:text="${reply.content}">댓글내용</li>
    <li th:text="${reply.writer}">작성자</li>
    <li th:text="${#temporals.format(reply.updatedDate, 'yyyy-MM-dd HH:mm:ss')}">작성일</li>
</ul>
	
<ol th:if="${rp.hasNext}"> <!-- hasNext: 가져올 아이템이 있는지를 확인하는 역할 -->
    <li>
        <button th:onclick="|replyList(${rp.page+1})|">더보기</button>
    </li>
</ol>

</html>

 

 

3. BoardController

댓글 작성 URL매핑 메서드와 댓글 조회 URL 매핑 메서드 생성

//댓글 작성
@PostMapping("/boards/{boardNo}/replies")
public ResponseEntity<Boolean> save(ReplyDTO dto) {
    service.saveProcess(dto);
    return ResponseEntity.ok().body(true);
}

//댓글 조회
//ajax-request
@GetMapping("/boards/{boardNo}/replies")
public String list(
        @PathVariable("boardNo") long no,
        @RequestParam(defaultValue = "1") int page,
        Model model) throws UnsupportedEncodingException {
    service.listProcess(no, page, model);

    return "board/reply";//html 이 응답데이터
}
  • return ResponseEntity.ok().body(true) : 댓글 저장이 성공했다는 HTTP 응답을 반환
  • return "board/reply" : "board/reply"라는 뷰 템플릿을 찾아 렌더링한다.. 댓글 목록이 HTML 응답 데이터로 전달된다.

 

 

4. BoardService

BoardService 인터페이스에 메서드 선언

//댓글 작성
void saveProcess(ReplyDTO dto);

//댓글 조회
void listProcess(long no, int page, Model model);

 

 

5. BoardServiceProcess

BoardService 인터페이스의 메서드 구현

//댓글 작성
@Override
public void saveProcess(ReplyDTO dto) {
    mapper.replySave(dto);
}

//댓글 조회
@Override
public void listProcess(long no, int page, Model model) {
    int limit=5;
    int offset=(page-1)*limit; // page=1 offset=0
    //게시글 번호에 해당하는 댓글 리스트를 가져와서 model 객체에 추가
    model.addAttribute("list", mapper.findAllByBoard_no(no,limit, offset));
    //총 댓글 개수
    int rowtotal=mapper.countByBoard_no(no);
    //페이지 정보 생성
    model.addAttribute("rp" ,PageData.create(page, limit, rowtotal));
}

 

 

6. BoardMapper

XML 파일에 정의된 쿼리를 호출할  메서드 선언

void replySave(ReplyDTO dto);

List<ReplyDTO> findAllByBoard_no(@Param("no") long no, @Param("limit") int limit, @Param("offset") int offset);

@Select("select count(*) from reply where board_no=#{no}")
int countByBoard_no(long no);

 

 

7. board-mapper.xml

동적 쿼리 작성

<!-- 댓글 작성 -->
<insert id="replySave">
    insert into reply(content,writer,board_no) values(#{content}, #{writer}, #{boardNo})
</insert>

<select id="findAllByBoard_no">
    select * from reply where board_no=#{no} order by no desc
    limit #{offset},#{limit}
</select>

 

 

8. 댓글 구현 화면

728x90