일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Oracle
- hikaricp
- 게시판 List
- 환경설정
- Connection pool
- Controller
- service
- MVC
- CRUD
- mybatis
- 게시판만들기
- MVC 게시판
- update
- jdbc
- MVC설정
- 게시판
- 서비스계층
- log4j
- spring
- Oracle 연결
- log4jdbc
- delete
- MVC CRUD
- Today
- Total
yahayaha
24. 댓글 페이징처리. 본문
댓글의 숫자가 많으면 데이터베이스에서 많은 양의 데이터를 가져와야함. 하지만 이는 성능상의 문제를 가져올 수 있음.
그래서 이런 문제는 일반적으로 페이징 처리를 이용함.
댓글에 대해서 우선적으로 고려해야 하는 일은 tbl_reply 테이블을 접근할 때 댓글의 번호(rno)가 중심이 아니라, 게시물의 번호(bno)가 중심이 되어야함.
인덱스 이용해서 페이징 처리하기
인덱스를 이용하는 이유 중에 하나는 정렬을 피할 수 있기 때문.
ReplyMapper.xml에 댓글을 페이징 처리하는 쿼리문을 추가.
<select id="getListWithPaging" resultType="org.zerock.domain.ReplyVO">
<![CDATA[
select rno, bno, reply, replyer, replyDate, updatedate
from
(
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}
)where rn > (#{cri.pageNum} - 1) * #{cri.amount}
]]>
</select>
부등호를 사용하기위해<![CDATA[ --- ]]> 사용 그럼 쿼리문이 잘 동작하는지 테스트를 진행.
@Test
public void testList2() {
Criteria cri = new Criteria(2, 10);
List<ReplyVO> replies = mapper.getListWithPaging(cri, 2461L);
replies.forEach(reply -> log.info(reply));
}
테스트 결과를 확인 후 이제 댓글을 페이징 처리 하기 위한 게시물 전체의 댓글 숫자를 파악해야함.
ReplyMapper 인터페이스에 매서드를 추가.
public int getCountByBno(Long bno);
그리고 ReplyMapper.xml에 id속성값이 getCountByBno인 select를 추가.
<select id="getCountByBno" resultType="int">
<![CDATA[
select count(rno) from tbl_reply where bno = #{bno}
]]>
</select>
댓글 전체를 보여주는 방식과 다르게 댓글의 페이징 처리는 댓글의 목록과 함께 전체 댓글 수를 같이 전달해야함.
ReplyService 인터페이스와 구현 클래스인 ReplyServiceImpl 클래스는 List<ReplyVO>와 댓글의 수를 같이 전달 가능한 구조로 변경.
두가지 정보를 담을 수 있는 ReplyPageDTO 클래스를 생성.
@Data
@AllArgsConstructor
@Getter
public class ReplyPageDTO {
private int replyCnt;
private List<ReplyVO> list;
}
객체 생성 시에 편하게 @AllArgsConstructor를 이용해서 replyCnt와 list를 생성자의 파라미터로 처리.
ReplyService 인터페이스와 replyServiceImpl 클래스에는 ReplyPageDTO를 반환하는 메서드 추가.
// service
public ReplyPageDTO getListPage(Criteria cri, Long bno);
//serviceImpl
@Override
public ReplyPageDTO getListPage(Criteria cri, Long bno) {
return new ReplyPageDTO(
mapper.getCountByBno(bno),
mapper.getListWithPaging(cri, bno));
}
그럼 이제 ReplyController에서 ReplyService에 새롭게 추가된 getListPage()를 호출 후 데이터를 전송하는 형태로 수정.
@GetMapping(value = "/pages/{bno}/{page}",
produces = {
MediaType.APPLICATION_XML_VALUE,
MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<ReplyPageDTO> getList(
@PathVariable("page") int page,
@PathVariable("bno") Long bno){
log.info("getList............");
Criteria cri = new Criteria(page,10);
log.info("리플 리스트 번호" + bno);
log.info(cri);
return new ResponseEntity<>(service.getListPage(cri, bno), HttpStatus.OK);
}
기존처럼 JSON 데이터를 전송하지만 ReplyPageDTO 객체를 JSON으로 전상하게 됨.
특정 게시물의 댓글 목록을 조화하면 replyCnt랑 list라는 이름의 속성을 가지는 JSON 문자열 전송.
그럼 본격적으로 화면 처리를 해야함.
화면 처리같은 경우는
1. 게시물을 조회하는 페이지에 들어오면 기본적으로 가장 오래된 댓글을 1페이지에 보여줌.
2. 1페이지의 게시물을 가져올 때 해당 게시물의 댓글의 숫자를 파악해서 댓글의 페이지 번호 출력.
3. 댓글이 추가되면 댓글의 숫자만을 가져와서 최종페이지를 찾아서 이동.
4. 댓글의 수정과 삭제 후에는 동일 페이지 호출.
ajax로 가져오는 데이터가 replyCnt와 list 데이터로 구성되어 있어서 reply.js도 수정이 필요.
function getList(param, callback, error){
var bno = param.bno;
var page = param.page || 1;
$.getJSON("/replies/pages/" + bno + "/" + page + ".json",
function(data){
console.log(data);
console.log("replyService getList...");
if(callback){
callback(data.replyCnt, data.list);
}
}).fail(function(xhr, status, err){
if(error){
error();
}
});
}
기존 callback 함수에 해당 게시물의 댓글 수 와 페이지에 해당하는 댓글 데이터를 전당하도록 하는데 화면에 대한 처리는 get.jsp에서 함.
function showList(page){
console.log("show list : " + page);
replyService.getList({bno:bnoValue,page: page||1}, function(replyCnt, list){
console.log("replyCnt : " + replyCnt);
console.log("list : " + list);
console.log(list);
if(page == -1){
pageNum = Math.ceil(replyCnt / 10.0);
showList(pageNum);
return;
}
var str="";
if(list == null || list.length == 0){
return
}
for(var i = 0, len = list.length || 0; i < len; i++){
str += "<li class='left clearfix' data-rno='"+list[i].rno+"'>";
str += "<div><div class='header'><strong class='primary-font'>["+list[i].rno+"]"+list[i].replyer+"</strong>";
str += "<small class='pull-right text-muted'>"+replyService.displayTime(list[i].replyDate)+"</small></div>";
str += " <p>"+list[i].reply+"</p></div></li>";
}
replyUL.html(str);
}); //end function
}//end showList
modalRegisterBtn.on("click", function(e){
var reply = {
reply: modalInputReply.val(),
replyer: modalInputReplyer.val(),
bno:bnoValue
};
replyService.add(reply, function(result){
alert(result);
modal.find("input").val("");
modal.modal("hide");
showList(-1);
});
});
showList() 함수는 파라미터로 전달되는 page 변수를 이용해서 원하는 댓글 페이지를 가져옴.
이때 만일 page 번호가 -1로 전달되면 마지막 페이지를 찾아서 다시 호출.
사용자가 새로운 댓글 추가하면 showList(-1); 호출해서 전체 댓글 숫자를 파악.
마지막 페이지를 호출해서 이동시키는 방식으로 동작.
댓글은 화면상 댓글이 출력되는 아래쪽에 자리 잡기에 <div>를 추가해줌.
<div class="panel-body">
<ul class="chat">
</ul>
</div>
<div class="panel-footer">
</div>
추가된 div에 댓글 페이지 번호를 출력하는 로직을 추가.
function showReplyPage(replyCnt){
var endNum = Math.ceil(pageNum / 10.0) * 10;
var startNum = endNum - 9;
var prev = startNum != 9;
var next = false;
if(endNum * 10 >= replyCnt){
endNum = Math.ceil(replyCnt/10.0);
}
if(endNum * 10 < replyCnt){
next = true;
}
var str = "<ul class = 'pagination pull-right'>";
if(prev){
str += "<li class = 'page-item'><a class='page-link' href='"+(startNum -1)+"'>Previous</a></li>";
}
for(var i = startNum; i <= endNum; i++){
var active = pageNum == i? "active":"";
str += "<li class='page-item "+active+" '><a class='page-link' href='"+i+"'>"+i+"</a></li>";
}
if(next){
str += "<li class='page-item'><a class='page-link' href='"+(endNum + 1)+"'>Next</a></li>";
}
str += "</ul></div>";
console.log(str);
replyPageFooter.html(str);
}
showReplyPage는 기존에 Java로 작성되는 PageMaker의 JavaScript버전.
댓글 페이지를 문자열로 구성한 후 div의 innerHTML로 추가. showList 마지막에 추가를 해줌.
function showList(page){
............
replyUL.html(str);
showreplyPage(replyCnt);
}); //end function
}//end showList
작업이 끝난 뒤 화면을 확인.
이제 남은건 페이지 번호를 클릭했을 때 새로운 댓글을 가져오도록 하는 부분을 처리
replyPageFooter.on("click","li a", function(e){
e.preventDefault();
console.log("page click");
var targetPagenum = $(this).attr("href");
console.log("targetPageNum : " + targetPagenum);
pageNum = targetPagenum;
showList(pageNum);
});
function showReplyPage(replyCnt){
............
}
위치를 정확하게 잡을것.
댓글의 페이지 번호는 a 태그 내에 존재. 이벤트 처리에서는 a 태그의 기본 동작을 제한하고, 댓글 페이지 번호를 변경한 후 해당 페이지의 댓글을 가져옴.
마지막으로 댓글이 페이징 처리가 되고 댓글의 수정과 삭제를 한 뒤에도 현재 댓글이 포함된 페이지로 이동 하도록 수정.
modalModBtn.on("click", function(e){
var reply = {rno:modal.data("rno"), reply: modalInputReply.val()};
replyService.updata(reply, function(result){
alert(result);
modal.modal("hide");
showList(pageNum);
});
});
modalRemoveBtn.on("click", function(e){
var rno = modal.data("rno");
replyService.remove(rno, function(result){
alert(result);
modal.modal("hide");
showList(pageNum);
});
});
showList를 호출할 때 보고있는 댓글 페이지의 번호를 호출하게함. 브라우저에서 댓글 등록, 수정, 삭제 작업은 모두 페이지 이동을함.
이렇게 댓글 작업을 끝마침.
하지만 지금 무작위 수정과 삭제가 가능한건 추후 스프링 시큐리티에서 점목할거라 그냥 모두 수정이 가능한채로 둔것.
'spring > 프로젝트' 카테고리의 다른 글
26. ajax 파일 업로드 (파일 확장자, 크기 처리, 년/월/일 폴더 처리, UUID 중복 파일 처리) (0) | 2024.02.15 |
---|---|
25. ajax 파일 업로드 (0) | 2024.02.14 |
23. 댓글 기능( 이벤트 , view 처리) (2) | 2024.02.11 |
22. ajax 댓글 처리 (0) | 2024.02.09 |
21. 댓글 처리하기 (Controller 처리) (0) | 2024.02.08 |