본문 바로가기
개발입문/SPRING 게시판 만들기

[SPRING] 댓글 페이징 처리, 댓글 총 개수 보여주기

by 양히◡̈ 2022. 10. 13.

댓글이 10개를 초과한다면, 댓글을 다음 페이지로 넘기는 처리를 해볼 것이다.

그 작업을 위해 일단 1페이지에 댓글이 10개까지만 보이도록 할 것이므로, 확인해보기 위해 한 게시글에 댓글이 10개 이상 있어야 한다.

그러므로 페이지에서 댓글을 10개가 초과할 때 까지 추가한다.

 

 

 

댓글목록 조회 인덱스 설계

댓글 목록이 'bno'가 기준이 되어야 하므로, 데이터의 양이 많아졌을 때 성능이 저하되는 것을 고려하여 'bno'를 기준으로 하는 인덱스를 먼저 설계해야 한다.

replyMapper.xml 에서 id가 getListWithPaging 인 select를 수정한다.

<select id="getListWithPaging"
    resultType="kr.icia.domain.ReplyVO">
    select rno, bno, reply, replyer, replydate, updatedate
    from
    <![CDATA[
    (select /*+INDEX(tbl_reply idx_reply)*/
    rownum rn, rno, bno, reply, replyer, replyDate, updatedate
    from tbl_reply
    where bno=#{bno}
    and rno > 0
    and rownum <= #{cri.pageNum} * #{cri.amount}
    order by rno
    ) where rn > (#{cri.pageNum}-1) * #{cri.amount}
    ]]>
</select>

 

쿼리문이 정상 작동하는지 테스트해보기 위해
ReplyMapperTests.java 에서 기존 Test 코드는 주석처리하고 새로운 Test코드를 작성한다.

@Test
public void testList2() {
    Criteria cri = new Criteria(2,10);

    List<ReplyVO> replies = mapper.getListWithPaging(cri, 800L);

    replies.forEach(reply->log.info(reply));
}

 

800번 게시글의 댓글 2페이지를 출력하도록 작성했다.

JUnit 테스트를 구동해 보면, 콘솔에 다음과 같이 보여지는 것을 볼 수 있다.

서버 구동 후 확인해보면, 댓글이 10개 이상인 게시글에서 댓글이 10개까지만 보여지는 것을 확인할 수 있다.

 

 

 

 

특정 게시물의 전체 댓글 개수 조회

댓글을 페이징처리하기 위해서 해당 게시물의 전체 댓글의 숫자를 파악해서 화면에 보여줄 필요가 있다.

ReplyMapper.java 에 메소드의 원형을 추가한다.

public int getCountByBno(Long bno); //게시물별 댓글 총개수 파악

ReplyMapper.xml 에서는 id속성값이 getCountByBno인 <select>를 추가한다.

<!-- 게시물별 댓글 총 개수 리턴 -->
<select id="getCountByBno" resultType="int">
    select count(rno) from tbl_reply where bno=#{bno}
</select>

 

 

 

댓글 페이징 처리는 댓글 목록과 함께 전체 댓글의 수를 같이 전달해야 한다.

댓글 페이징에 필요한 정보를 담을 새로운 DTO를 생성한다.

src/main/java > kr.icia.domain > new Class 생성 > name: ReplyPageDTO

package kr.icia.domain;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;

@Data
@AllArgsConstructor
@Getter
public class ReplyPageDTO {
	private int replyTotalCnt; //댓글의 개수
	private List<ReplyVO> list; //댓글의 목록
}

 

ReplyService 인터페이스와 그의 구현 클래스인 ReplyServiceImp 클래스에 ReplyPageDTO를 반환하는 메소드를 추가할 것이다.

ReplyService 에 추가한다.

//댓글의 목록과 게시물의 개수
public ReplyPageDTO getListPage(Criteria cri, Long bno);

ReplyServiceImp 에 추가한다.

@Override
public ReplyPageDTO getListPage(Criteria cri, Long bno) {
    //각각의 매퍼를 이용하여 댓글의 개수와 댓글의 목록을 추출
    return new ReplyPageDTO(mapper.getCountByBno(bno), mapper.getListWithPaging(cri, bno));
}

 

 

이제 생성된 메소드를 호출할 것이다.

ReplyController 에 댓글 목록 가져오기 부분을 수정한다.

 

// 댓글 목록 가져오기
@GetMapping(value = "/pages/{bno}/{page}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ReplyPageDTO> getList(@PathVariable("page") int page, @PathVariable("bno") Long bno) {
    // @PathVariable: url로 넘겨받은 값을 이용
    log.info("getList......");
    Criteria cri = new Criteria(page, 10);
    log.info(cri);

    return new ResponseEntity<>(service.getListPage(cri, bno), HttpStatus.OK);
    // T<List<ReplyVO>> t = new T<>();
    // 댓글 목록을 출력하고, 정상처리 상태를 return함
}

 

기존과 동일하게 JSON 데이터를 전송하지만 ReplyPageDTO 객체를 JSON으로 전송 하게 되므로, 특정 게시물의 댓글 목록을 조회하면 아래와 같이 'replyCnt'와 list'라는 이름의 속성을 가지는 JSON 문자열이 전송된다.

 

 

 

 

총 개수를 콘솔에 표시하기

reply.js 에서 '댓글 목록 가져오기'부분의 콜백을 주석처리한다.

그 아래에 코드를 추가한다.

//callback(data); //댓글 목록만 가져오는 경우
callback(data.replyTotalCnt, data.list); //댓글 숫자와 목록을 가져오는 경우

 

reply.js 를 이용해서 댓글의 페이지를 호출하는 부분은 showList 함수이므로, 페이지번호를 출력하도록 수정해야 한다.

 

get.jsp 에서 function showList() 를 수정한다.

function showList(page){
    replyService.getList({
        ...
        function(list) {
            ...
    })
}

기존에는 list만 받았는데, 이제 replyTotalCnt도 받을 수 있도록 추가하고, 펑션 안에 코드를 추가한다.

function(replyTotalCnt, list) {
    console.log("replyCnt : " + replyTotalCnt);
    if (page == -1) {
        pageNum = Math.ceil(replyTotalCnt / 10.0);
        //페이지 번호가 음수라면, 댓글의 마지막 페이지 구하기
        showList(pageNum);
        return;
    }

 

showlist()는 파라미터로 전달되는 page변수를 이용해서 원하는 댓글 페이지를 가져오게 된다.

이 때, page 번호가 '-1'로 전달되면 마지막 페이지를 찾아서 다시 호출하게 된다.

사용자가 새로운 댓글을 추가하면 showList(-1);을 호출하여 우선 전체 댓글의 숫자를 파악하게 하고, 다시 마지막 페이지를 호출해서 이동시키는 방식으로 동작시킨다.

그러기 위해 방금 수정한 showList 펑션 맨 아래 부분의 showList(1)을 showList(-1)으로 바꾸어준다.

function showList(page){
	...
}
showList(-1);

서버 구동 후, 콘솔에 댓글의 총 개수가 표시되고 있다.

또한, 게시글 읽기 페이지에서 댓글은 마지막 페이지를 보여주게 된다.

 

 

 

 

댓글 페이지번호 화면에 나타내기

댓글의 마지막 페이지를 보여주는 단계까지 완료했다.

그럼 이제 이전 댓글 페이지도 볼 수 있도록 페이지 버튼을 만들어야 한다.

get.jsp의 스크립트에서 showList() 메소드 안에 showReplyPage() 호출 부분을 추가한다.

function showList(page){
    replyService.getList({
        ...
        showReplyPage(replyTotalCnt);
    })
}

 

호출한 함수를 구현한다. (showList() 아래에)

/* 댓글 페이징 시작 */
var pageNum = 1;
var replyPageFooter = $(".panel-footer");

function showReplyPage(replyCnt) {
    var endNum = Math.ceil(pageNum/10.0) * 10;
    //pageNum이 1이라고 가정하면 Math.ceil(1/10.0)*10 을 하면 endNum이 10이 나온다
    var startNum = endNum - 9; 
    var prev = startNum != 1; //startNum이 1이 아니라면 prev가 만들어진다
    var next = false;

    if (endNum * 10 >= replyCnt) {
        endNum = Math.ceil(replyCnt / 10.0);
    }
    if (endNum * 10 < replyCnt) {
        next = true;
    }
    var str = "<ul class='pagination";
    str+= " justify-content-center'>";

    if (prev) {
        str += "<li class='page-item'><a ";
        str += "class='page-link' href='";
        str += (startNum -1);
        str += "'>이전</a></li>";
    }
    for (var i = startNum; i <= endNum; i++) {
        var active = pageNum == i ? "active" : "";
        str += "<li class='page-item " + active
        +"'><a class='page-link' ";
        str += "href='" + i + "'>" + i + "</a></li>";
    }
    if (next) {
        str += "<li class='page-item'>";
        str += "<a class='page-link' href='";
        str += (endNum + 1) + "'>다음</a></li>";
    }
    str += "</ul>";
    console.log(str);
    replyPageFooter.html(str);
}
/* 댓글 페이징 끝 */

 

댓글 페이지 번호가 나오는 것 까지는 성공했다.
하지만 아직 페이지 이동은 정상적으로 되지 않는다.

 

 

 

 

댓글 페이지 이동 처리

이제 페이지 번호를 클릭했을 때 페이지가 이동되도록 처리할 것이다.

get.jsp 스크립트에 추가한다.

//댓글 페이지번호 클릭시 이동 처리
replyPageFooter.on("click", "li a", function(e) {
    e.preventDefault();
    var targetPageNum = $(this).attr("href");
    pageNum = targetPageNum;
    showList(pageNum);
});

1번 페이지를 누르면 페이지가 정상적으로 이동된다.

 

 

 

댓글 개수를 목록에서 제목 옆에 표시하기

해당 게시글에 댓글이 있으면 댓글 개수를 목록에서도 확인할 수 있도록 해볼 것이다.

먼저, tbl_board에 리플 개수 컬럼을 추가하기 위해

sql developer 의 admin 계정으로 접속하여 다음 쿼리문을 작성한다.

ALTER TABLE tbl_board ADD (
    replycnt NUMBER DEFAULT 0
);
--게시물 테이블에 replycnt 컬럼을 추가하면서 초기값은 0으로 설정
UPDATE tbl_board
SET
    replycnt = (
        SELECT
            COUNT(rno)
        FROM
            tbl_reply
        WHERE
            tbl_reply.bno = tbl_board.bno
    );
--게시판의 replycnt에 댓글 테이블의 게시물별 총 댓글 개수를 계산하여 replycnt에 적용
COMMIT;

tbl_board 에 replycnt 컬럼이 추가되었고 댓글의 수가 잘 표시되고 있다.

 

BoardVO.java 를 열어 replycnt를 추가한다. (다시말하지만, mybatis를 이용해 게터와 세터는 자동 생성하고 있다)

private int replyCnt;

 

댓글이 추가될 때마다 댓글의 개수를 업데이트해야 하므로,

BoardMapper.java 에 추가한다.

public int updateReplyCnt(@Param("bno") Long bno, @Param("amount") int amount);

BoardMapper.xml 에서 id 속성값이 getListWithPaging 인 곳을 찾아 select 문에 replycnt를 추가한다.

 

 

댓글이 추가되거나 삭제되면 댓글의 총 개수가 변화해야하므로 이 부분을 구현해볼 것이다.

update 속성값을 가진 코드를 추가한다.

 

<update id="updateReplyCnt">
    update tbl_board set replycnt = replycnt + #{amount}
    where bno = #{bno}
</update>

 

ReplyServiceImp.java 에 BoardMapper를 명시해준다.

@Setter(onMethod_ = @Autowired)
private BoardMapper boardMapper;

 

그리고 registerremove 부분을 각각 아래와 같이 수정한다.

@Transactional
@Override
public int register(ReplyVO vo) {
    log.info("register......" + vo);
    boardMapper.updateReplyCnt(vo.getBno(), 1);
    //댓글이 등록된다면 게시물 테이블의 댓글 총개수가 1증가
    return mapper.insert(vo);
}
@Transactional
@Override
public int remove(Long rno) {
    log.info("remove......" + rno);
    ReplyVO vo = mapper.read(rno);
    boardMapper.updateReplyCnt(vo.getBno(), -1);
    return mapper.delete(rno);
}

@Transactional Refereunce ▶ [Spring] @Transactional 사용시 주의해야할 점 :: 개발자로 홀로 서기 (tistory.com)

 

 

list.jsp 에서 목록에 게시글이 표시되는 부분을 추가할 것이다.

빨간색으로 표시된 부분을 나누어 사이에 코드를 입력한다.

 
<c:if test="${board.replyCnt ne 0 }">
    <span style="color:red;">[<c:out value="${board.replyCnt }"/>]</span>
</c:if>

 

댓글의 개수가 표시되며, 새 댓글을 작성하거나 삭제하면 숫자가 변경된다.

 

 

 

 

댓글 수정/삭제 후 현재 댓글 페이지 유지하기

댓글을 수정/삭제한 후에 페이지가 풀리는 것을 보완하기 위해 get.jsp에서 댓글 수정 부분과 삭제 부분의 스크립트를 일부 수정한다.

showList(-1) 부분을 showList(pageNum)으로 변경하기만 하면 된다.

 

댓글