Spring 게시판 만들기(23)
댓글기능 2 목록 요청작업
handlebars 기능 추가
<!-- 자바스크립트 handlebas 최신 -->
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
handlebars 연습
동작은 안됨
https://jsfiddle.net/eu81273/Lqg0yrve/ 참조
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
<script id="demo-template" type="text/x-handlebars-template">
<table>
<thead>
<th>이름</th>
<th>아이디</th>
<th>메일주소</th>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</script>
<script>
// 핸들바 템플릿 가져오기
let source = $("#demo-template").html();
// 핸들바 템플릿 컴파일
let template = Handlebars.compile(source);
//핸들바 템플릿에 바인딩할 데이터
// 데이터. 실제작업은 스프링에서 JSON형식으로 받을 것
let data = {
users: [
{name:"홍길동1", id:"user01", email:"user01@abc.com"},
{name:"홍길동2", id:"user02", email:"user02@abc.com"},
{name:"홍길동3", id:"user03", email:"user03@abc.com"},
{name:"홍길동4", id:"user04", email:"user04@abc.com"},
{name:"홍길동5", id:"user05", email:"user05@abc.com"}
]
};
// 핸들바 템플릿에 데이터를 바인딩해서 HTML 생성
let html = template(data);
// 생성된 HTML을 DOM에 주입
$("body").append(html);
</script>
</head>
<body>
</body>
</html>
ReplyController RestAPI 활용 주소 넣기
// 1) 댓글목록데이터, 2) 페이징정보를 JSON포맷으로 클라이언트에게 리턴해주는 작업
// 주소 : /pages/{bno}/{page}. 주소의 일부분을 파라미터값으로 사용하고자 할 경우
// 예> /page/1/1
@GetMapping(value = "/pages/{bno}/{page}", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public ResponseEntity<Map<String, Object>> getList(@PathVariable("page") int page,@PathVariable("bno") Long bno){
ResponseEntity<Map<String, Object>> entity = null;
Map<String, Object> map = new HashMap<String, Object>();
// 1) 댓글목록 작업
// 2) 페이징정보 작업
return entity;
}
ReplyMapper.xml에 SQL 구문 작업
<select id="getListWithPaging" resultType="com.demo.domain.ReplyVO">
<![CDATA[
SELECT RN, RNO, BNO, REPLY, REPLYER, REPLYDATE, UPDATEDATE
FROM (
SELECT /*+ INDEX_DESC(TBL_REPLY PK_REPLY)*/ ROWNUM RN, RNO, BNO, REPLY, REPLYER, REPLYDATE, UPDATEDATE FROM TBL_REPLY
WHERE BNO = #{bno} AND ROWNUM <= (#{cri.pageNum} * #{cri.amount})
)
WHERE RN > ((#{cri.pageNum}-1) * #{cri.amount})
]]>
</select>
<select id="getCountByBno" resultType="int">
select count(*) from TBL_REPLY where bno = #{bno}
</select>
ReplyMapper 인터페이스
// Criteria cri : 페이징파라미터, Long bno : 게시판글번호(본문글)
// MAPPER INTERFACE의 메서드 파라미터가 2개이상일 경우 @Param 어노테이션을 사용해야 한다.(중요)
List<ReplyVO> getListWithPaging(@Param("cri") Criteria cri, @Param("bno") Long bno);
// 본문글을 참조하는 댓글 데이터 개수
int getCountByBno(Long bno);
이후 2개의 메서드를 하나씩 서비스로 보내도 되지만 같은 속성을 묶어서 진행한다
ReplyPageDTO domain 생성
package com.demo.domain;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor // 모든 필드를 파라미터로 하는 생성자메서드
public class ReplyPageDTO {
private int replyCnt;
private List<ReplyVO> list;
// @AllArgsConstructor 으로 인해 아래것이 만들어짐
// public ReplyPageDTO(int replyCnt, List<ReplyVO> list) {
//
// this.replyCnt = replyCnt;
// this.list = list;
// }
}
이후 Service에 하나로 메서드를 가져온다
ReplyPageDTO getListPage(Criteria cri, Long bno);
이후 ReplyServiceImpl에 하나로 등록
@Override
public ReplyPageDTO getListPage(Criteria cri, Long bno) {
// TODO Auto-generated method stub
return new ReplyPageDTO(mapper.getCountByBno(bno), mapper.getListWithPaging(cri, bno));
}
다시 컨트롤러에서 받아와서 jsp로 전달해준다
//1)댓글목록데이타, 2)페이징정보를 JSON포맷으로 클라이언트에게 리턴해주는 작업
// 주소: /pages/{bno}/{page}. 주소의 일부분을 파라미터값으로 사용하고자 할경우
// 예> /pages/5120/1
// 테스트주소: http://localhost:9090/replies/pages/5120/1.json
@GetMapping(value = "/pages/{bno}/{page}", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
public ResponseEntity<Map<String, Object>> getList(@PathVariable("bno") Long bno, @PathVariable("page") int page){
ResponseEntity<Map<String, Object>> entity = null;
Map<String, Object> map = new HashMap<String, Object>();
//1)댓글목록작업. 클릭된 번호 page
Criteria cri = new Criteria(page, 5);
ReplyPageDTO replyObj = service.getListPage(cri, bno);
map.put("list", replyObj.getList());
//2)페이징정보작업
PageDTO pageDTO = new PageDTO(cri, replyObj.getReplyCnt());
map.put("pageMaker", pageDTO);
entity = new ResponseEntity<Map<String,Object>>(map, HttpStatus.OK);
return entity;
}
더미데이터 넣고 확인하기 bno는 자기가 넣을 댓글 글번호
-- 댓글 더미데이터 삽입
INSERT INTO TBL_REPLY(rno, BNO, REPLY, REPLYER)
SELECT SEQ_REPLY.NEXTVAL, BNO, REPLY, REPLYER FROM TBL_REPLY WHERE BNO = 2163;
-- 더미데이터 확인
SELECT RNO, BNO, REPLY, REPLYER FROM TBL_REPLY WHERE BNO = 2163;
이후 postman에서 확인해보기
get.jsp 댓글목록 요청작업
<script>
// 댓글목록 요청작업(댓글+페이징기능)
let bno = ${board.bno}; //본문 글번호
let replyPage = 1;
let url = "/replies/pages/" + bno + "/" + replyPage + ".json"; // 댓글목록및 페이징정보 요청주소
getPage(url);
//댓글목록출력작업
//파라미터 설명
/*
replyData : 댓글목록 데이타, target : 댓글이 삽입될 태그위치, templateObj : 핸들바 템플릿 참조객체
*/
let printData = function(replyData, target, templateObj) {
let template = Handlebars.compile(templateObj.html());
let html = template(replyData);
target.empty();
target.append(html);
}
//ajax구문으로 요청하는 작업.
function getPage(url){
console.log(url);
$.getJSON(url, function(data){
//console.log(data);
/*
data.list : 댓글목록데이타, data.pageMaker : 댓글페이징정보
*/
printData(data.list, $("#replyList"), $("#reply-template"));
});
//댓글목록 출력기능 함수
//댓글페이징출력기능 함수
}
</script>
handlebar template : 목록작업
<script id="reply-template" type="text/x-handlebars-template">
<div class="form-group">
<label for="replyer">작성자</label>
<input type="hidden" id="rno" name="rno" value="">
<input type="text" class="form-control" id="replyer" value="" readonly>
</div>
<div class="form-group">
<label for="reply">등록일: </label>
<textarea class="form-control" id="reply" rows="3" readonly></textarea>
</div>
</script>
<!-- 등록일 앞에 날짜표시넣기 핸들바 -->
<script>
//사용자정의 Helper. 용도: 댓글 작성일 밀리세컨드 데이타를 날짜포맷을 변환(2022/06/27)
Handlebars.registerHelper("prettifyDate", function(timeValue){
const date = new Date(timeValue);
return date.getFullYear() + "/" +date.getMonth() + "/" + date.getDate();
});
</script>
댓글 페이징 출력작업 추가
자바스크립트 작업과 그에 해당하는 폼에 넣기
댓글페이징 출력 폼을 기준으로 작성
<!-- 댓글 페이징 출력-->
<div id="replyPaging">
</div>
댓글작업 자바스크립트 추가
<script>
// 댓글목록 요청작업(댓글+페이징기능)
let bno = ${board.bno}; //본문 글번호
let replyPage = 1;
let url = "/replies/pages/" + bno + "/" + replyPage + ".json"; // 댓글목록및 페이징정보 요청주소
getPage(url);
// 1) 글목록출력작업
//파라미터 설명
/*
replyData : 댓글목록 데이타, target : 댓글이 삽입될 태그위치, templateObj : 핸들바 템플릿 참조객체
*/
let printData = function(replyData, target, templateObj) {
let template = Handlebars.compile(templateObj.html());
let html = template(replyData);
target.empty();
target.append(html);
}
// 2) 댓글 페이징 출력작업
// pageMaker : 페이징정보, target : 출력될 위치
let printPaging = function(pageMaker, target){
// <nav aria-label="Page navigation example">
// <ul class="pagination">
// <li class="page-item"><a class="page-link" href="#">Previous</a></li>
// <li class="page-item"><a class="page-link" href="#">1</a></li>
// <li class="page-item"><a class="page-link" href="#">Next</a></li>
// </ul>
// </nav>
let pagingStr = '<nav aria-label="Page navigation example">';
pagingStr += '<ul class="pagination">';
// 이전 표시 작업
if(pageMaker.prev){
pagingStr += '<li class="page-item"><a class="page-link" href="' + (pageMaker.startPage - 1);
pagingStr += '">Previous</a></li>';
}
// 페이지번호 표시작업
for(let i=pageMaker.startPage; i<=pageMaker.endPage; i++){
let strClass = (pageMaker.cri.pageNum == i) ? 'active' : ''; // 현재페이지 style
pagingStr += '<li class="page-item ' + strClass + '"><a class="page-link" href="' + i + '">' + i + '</a></li>';
}
// 다음 표시 작업
if(pageMaker.next) {
pagingStr += '<li class="page-item"><a class="page-link" href="' + (pageMaker.endPage + 1);
pagingStr += '">Next</a></li>';
}
pagingStr += '</ul>';
pagingStr += '</nav>';
// target 변수가 가리키는 위치에 pagingStr 변수의 내용을 삽입
target.html(pagingStr);
}
//ajax구문으로 요청하는 작업.
function getPage(url){
console.log(url);
$.getJSON(url, function(data){
//console.log(data);
/*
data.list : 댓글목록데이타, data.pageMaker : 댓글페이징정보
*/
//댓글목록 출력기능 함수
printData(data.list, $("#replyList"), $("#reply-template"));
//댓글페이징출력기능 함수
printPaging(data.pageMaker, $("#replyPaging"));
});
}
</script>
2번 댓글작업에 해당 구문을 추가해서 댓글 페이징작업에 버튼작업을 활성화 시킨다
<script>
// 댓글 페이지번호 클릭. 동적인 태그를 이벤트 설정 할 경우에
$("#replyPaging").on("click", "ul.pagination li a", function(e){
e.preventDefault();
// console.log("클릭");
replyPage = $(this).attr("href"); // 1 2 3 4 5
let url = "/replies/pages/" + bno + "/" + replyPage + ".json"; // 댓글목록및 페이징정보 요청주소
getPage(url);
});
</script>
<script>
// 댓글목록에서 수정버튼 클릭시
$("#replyList").on("click", "input[name='btnModalModify']", function(){
// console.log("클릭");
// 현재 선택된 댓글 내용을 읽어와서, 모달대화상자에 보여준다
let rno = $(this).parents("div.box-body").find("input[name='rno']").val();
let replyer = $(this).parents("div.box-body").find("input[name='replyer']").val();
let reply = $(this).parents("div.box-body").find("textarea[name='reply']").val();
let replydate = $(this).parents("div.box-body").find("span").html();
// console.log(rno);
// console.log(replyer);
// console.log(reply);
// console.log(replydate);
// Modal Dialog의 내용물 수정
$("#replyTitle").html("Modify Reply");
$("#rno").val(rno);
$("#replyer").val(replyer);
$("#reply").val(reply);
$(".btnModal").hide(); // 모달대화상자의 3개버튼을 모두 보이지 않게
$("#btn_replyModify").show();
$("#replyModal").modal('show');
});
</script>
댓글남기기