- 네이버 지식인 게시글 상세페이지 댓글


맨 처음 댓글을 만들때 전에 했던대로 하면된다고 생각했지만
글작성자의 경우 질문 작성자로 사용자의 이름이 작성되어야하고
당연히 일정이상의 댓글이 달리는 경우 페이징까지 진행해야했습니다.
또한 댓글공간을 윈도우로드를 사용하였기 때문에 페이지가 넘어가면 새로고침되며
디스플레이가 none으로 바뀌는 상황으로 ajax를 사용해 비동기 처리를 진행해야 했습니다.
- boardDetail.jsp - 코멘트 작성 공간
게시글 상세페이지의 댓글 작성을 진행하는 공간입니다
로그인을 하지 않은경우 코멘트를 작성하는 공간을 클릭하면
로그인이 필요하다는 문구를 confirm을 사용하여 확인 취소를 받고
확인을 클릭하는 경우 로그인 페이지를 화면에 띄웁니다.
<div class="detail-contents-comment-box">
<fieldset style="border: 0;">
<div class="detail-contents-comment-inner">
<c:choose>
<c:when test="${memberDTO != null}">
<textarea class="detail-contents-comment-textarea" maxlength="1000"
id="detail-contents-comment-textarea"
placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."></textarea>
</c:when>
<c:otherwise>
<textarea class="detail-contents-comment-textarea" maxlength="1000"
id="detail-contents-comment-textarea"
placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."
onclick="plzLogin()"></textarea>
</c:otherwise>
</c:choose>
</div>
<div class="detail-contents-comment-textarea-bottom">
<c:choose>
<c:when test="${sessionScope.memberId != null}">
<button type="button" class="detail-contents-comment-textarea-btn"
id="bestbtn" style="cursor: pointer;"
onclick="commentSave(${BoardDTO.id},${BoardDTO.memberId})">
등록
</button>
</c:when>
<c:otherwise>
<button type="button" class="detail-contents-comment-textarea-btn"
id="notlogin" style="cursor: pointer;"
onclick="plzLogin()">등록
</button>
</c:otherwise>
</c:choose>
</div>
</fieldset>
</div>
- boardDetail.jsp - 댓글 List 공간
commentList의 페이징 List를 출력하는 공간
forEach문을 돌리면서 게시글의 memberId와 comment의 memberId가 같은경우
작성자의 이름을 질문 작성자로 변경합니다.
<span class="detail-contents-comment-list-box" id="detail-contents-comment-list-box">
<c:forEach items="${CommentList}" var="CommentList">
<div class="detail-contents-comment-list">
<p class="detail-contents-comment-title">
<c:choose>
<c:when test="${CommentList.memberId == BoardDTO.memberId}">
<strong>질문 작성자</strong>
</c:when>
<c:otherwise>
<strong>${CommentList.commentWriter}</strong>
</c:otherwise>
</c:choose>
</p>
<div class="detail-contents-comment-text">
${CommentList.commentContents}
</div>
<p class="detail-contents-comment-time">
<fmt:formatDate value="${CommentList.commentCreatedDate}"
pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
</p>
</div>
</c:forEach>
</span>
<div class="detail-contents-comment-paging">
<span id="detail-contents-comment-paging-bbtn-on"></span>
<div style="display: inline-block;" id="numResult">
<c:forEach begin="${CommentPaging.startPage}" end="${CommentPaging.endPage}" var="i"
step="1">
<c:choose>
<c:when test="${i eq CommentPaging.page}">
<a class="detail-contents-comment-paging-btn-off">${i}</a>
</c:when>
<c:otherwise>
<a onclick="commentNBBtn(${BoardDTO.id},${BoardDTO.memberId},${i})"
class="detail-contents-comment-paging-btn-on"
style="cursor: pointer">${i}</a>
</c:otherwise>
</c:choose>
<%--href="/board/detail?BoardId=${BoardDTO.id}&DetailPage=${i}"--%>
</c:forEach>
</div>
<span id="detail-contents-comment-paging-nbtn-on">
<c:choose>
<c:when test="${CommentPaging.maxPage <= 1}">
</c:when>
<c:otherwise>
<c:if test="${CommentPaging.page != CommentPaging.maxPage}">
<a class="detail-contents-comment-paging-nbtn-on"
onclick="commentNBBtn(${BoardDTO.id},${BoardDTO.memberId},${CommentPaging.page+1})"
style="cursor: pointer;">
<span>다음</span>
<i class="comment-next-icon"></i>
</a>
</c:if>
</c:otherwise>
</c:choose>
</span>
</div>
- boardDetail.jsp - script
댓글 공간을 보여주기 위한 함수
시작은 display none 이고 클릭하면 block 으로 바뀌며 보여짐
window.onload를 사용한 이유는 처음 시작에 두번 클릭해야하는 오류를
고치지 못했기 때문에 어쩔수 없이 사용함
window.onload = function () {
const openComment = document.getElementById('openComment');
const commentBox = document.getElementById('detail-contents-comment-area');
openComment.addEventListener("click", function () {
if (commentBox.style.display === "block") {
commentBox.style.display = "none";
} else {
commentBox.style.display = "block";
}
})
layout을 보여주기 위한 함수
시작은 댓글과 마찬가지로 display none이고
똑같이 두번 클릭해야하는 오류를 수정하지 못해 window onload를 사용함
const layoutController = document.getElementById('layout-controller');
const layoutBox = document.getElementById('layout-box');
layoutController.addEventListener("click", function () {
if (layoutBox.style.display === "block") {
layoutBox.style.display = "none";
} else {
layoutBox.style.display = "block";
}
})
}
댓글 작성에 사용된 함수
등록을 하면 바로 반영된 모습을 보여주기 위해
ajax를 사용하여 비동기 처리함
const commentSave = (boardid, boardMemberid) => {
댓글을 작성한 게시판의 id , 게시글을 작성한 사용자의 id를 매개변수로 받음
const commentWriter = '${memberDTO.memberEmail}';
댓글을 작성한 사용자의 email을 담은 변수
const commentContents = document.getElementById('detail-contents-comment-textarea').value;
댓글을 작성하는 textarea의 vlue를 가져오는 document 객체
const boardId = boardid;
댓글이 달린 게시판의 id를 담은 변수
const memberId = '${sessionScope.memberId}';
댓글을 작성한 사용자의 id
const commentResult = document.getElementById('detail-contents-comment-list-box');
페이징처리를 진행하고 받아온 List를 출력해줄 공간의 document 객체
const boardMemberId = boardMemberid;
게시판 작성자의 id를 담은 변수
const countResult = document.getElementById('detail-contents-comment-count');
댓글이 몇개 달렸는지 출력하는 태그의 document 객체
const commentPageDResult = document.getElementById('detail-contents-comment-paging-bbtn-on');
페이징의 "이전"버튼을 담고있는 태그의 document 객체
const commentPageUResult = document.getElementById('detail-contents-comment-paging-nbtn-on');
페이징의 "다음"버튼을 담고있는 태그의 document 객체
const commentNumPageOn = document.getElementById('numResult');
페이징의 숫자 버튼을 담고있는 태그의 document 객체
$.ajax({
type: "post",
url: "/comment/save",
data: {
"commentWriter": commentWriter,
"commentContents": commentContents,
"boardId": boardId,
"memberId": memberId
사용자가 작성한 댓글을 서버로 보내 저장후
비동기처리로 바로 반영된 모습을 보여줍니다.
},
success: function (res) {
let output = "";
페이징 처리된 List를 담아줄 output 변수
let commentCount = res.count;
댓글의 count를 담아주는 conmmentCount 변수
let downPut = "";
"이전"버튼을 담아줄 downPut 변수
let upPut = "";
"다음"버튼을 담아줄 upPut 변수
let numPut = "";
페이징된 숫자버튼을 담아줄 numPut 변수
downPut += '<a class="detail-contents-comment-paging-bbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page - 1) + ')" style="cursor: pointer;">' +
'<i class="comment-back-icon"></i>' + '<span> 이전</span>' + '</a>';
upPut += '<a class="detail-contents-comment-paging-nbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page + 1) + ')" style="cursor: pointer;">' + '<span>다음 </span>' + '<i class="comment-next-icon"></i>' + '</a>';
"다음" / "이전" 버튼을 문자열로 양식에 맞게 담아줍니다.
for (let i in res.comments) {
output += '<div class="detail-contents-comment-list">';
output += '<p class="detail-contents-comment-title">';
if (res.comments[i].memberId == boardMemberId) {
output += '<strong>질문 작성자</strong>';
} else {
output += '<strong>' + res.comments[i].commentWriter + '</strong>';
}
output += '</p>';
output += '<div class="detail-contents-comment-text">';
output += '<p>' + res.comments[i].commentContents + '</p>';
output += '</div>';
output += '<p class="detail-contents-comment-time">'
output += moment(res.comments[i].commentCreatedDate).format("YYYY-MM-DD HH:mm:ss");
output += '</p>';
output += '</div>';
}
여기까지가 코멘트 List의 정보를 for문을 사용하여
output에 문자열로 담아준 모습입니다.
for (let i = res.DetailCommentPage.startPage; i <= res.DetailCommentPage.endPage; i++) {
if (res.DetailCommentPage.page == i) {
numPut += '<a class="detail-contents-comment-paging-btn-off">' + i + '</a>';
} else {
numPut += '<a onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + i + ')" class="detail-contents-comment-paging-btn-on" style="cursor: pointer">' + i + '</a>';
}
}
여기까지가 페이징 처리가된 dto의 정보를
for문을 사용하여 numPut에 담아준 모습입니다.
if (res.DetailCommentPage.page <= 1) {
commentPageDResult.innerHTML = "";
} else if (res.DetailCommentPage.page > res.DetailCommentPage.startPage) {
commentPageDResult.innerHTML = downPut;
}
"이전"페이지 버튼의 경우 특정 상황에서는 보여지지 않아야하기 때문에
if문을 사용하여 paging된 정보와 비교하여 담아줍니다.
if (res.DetailCommentPage.page == res.DetailCommentPage.maxPage) {
commentPageUResult.innerHTML = "";
} else {
commentPageUResult.innerHTML = upPut;
}
"다음"페이지 버튼의 경우 특정 상황에서는 보여지지 않아야하기 때문에
if문을 사용하여 paging된 정보와 비교하여 담아줍니다.
commentNumPageOn.innerHTML = numPut;
countResult.innerHTML = commentCount;
commentResult.innerHTML = output;
document.getElementById('detail-contents-comment-textarea').value = "";
위에서 변수에 문자열로 담은 정보들을 각각의 위치의의 태그에
innerHTML을 사용하여 담아줍니다.
이후 댓글 작성 공간을 비워줍니다.
},
error: function () {
console.log("실패");
}
})
};
비로그인 상태에서 댓글 남기기를 시도하는 경우
로그인 후 이용하실 수 있다는 CONFIRM을 띄웁니다.
확인을 누르는 경우 로그인 페이지로 이동합니다.
const plzLogin = () => {
if (confirm("로그인 후 이용하실 수 있습니다.")) {
location.href = "/member/login";
}
}
코멘트List에서 페이지 이동을 시도한는 경우 사용되는 함수
const commentNBBtn = (boardid, boardMemberid, CommentPagingPage) => {
const DetailPage = CommentPagingPage;
사용자가 원하는 페이지의 정보를 담은 변수
const boardId = boardid;
해당 게시물의 id를 담은 변수
const boardMemberId = boardMemberid;
로그인된 사용자의 id를 담은 변수
const commentResult = document.getElementById('detail-contents-comment-list-box');
페이징 처리된 정보를 출력해주는 공간의 document객체를 담은 변수
const commentPageDResult = document.getElementById('detail-contents-comment-paging-bbtn-on');
"이전"페이지 버튼의 부모태그를 담은 document 객체를 담은 변수
const commentPageUResult = document.getElementById('detail-contents-comment-paging-nbtn-on');
"다음"페이지 버튼의 부모태그를 담은 document 객체를 담은 변수
const commentNumPageOn = document.getElementById('numResult');
페이징처리된 dto의 정보를 출력해줄 부모태그의 document 객체
$.ajax({
type: "post",
url: "/comment/UDPage",
data: {
"boardId": boardId,
"DetailPage": DetailPage,
},
success: function (res) {
let output = "";
페이징 처리된 List를 담아줄 output변수
let downPut = "";
"이전"페이지 버튼을 담아줄 downput 변수
let upPut = "";
"다음"페이지 버튼을 담아줄 upPut 변수
let numPut = "";
페이징된 dto정보를 담아줄 numPut 변수
downPut += '<a class="detail-contents-comment-paging-bbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page - 1) + ')" style="cursor: pointer;">' +
'<i class="comment-back-icon"></i>' + '<span> 이전</span>' + '</a>';
upPut += '<a class="detail-contents-comment-paging-nbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page + 1) + ')" style="cursor: pointer;">' + '<span>다음 </span>' + '<i class="comment-next-icon"></i>' + '</a>';
"이전" / "다음" 버튼의 양식을 문자열로 각 변수에 담아줍니다.
for (let i in res.commentDTOList) {
output += '<div class="detail-contents-comment-list">';
output += '<p class="detail-contents-comment-title">';
if (res.commentDTOList[i].memberId == boardMemberId) {
output += '<strong>질문 작성자</strong>';
} else {
output += '<strong>' + res.commentDTOList[i].commentWriter + '</strong>';
}
output += '</p>';
output += '<div class="detail-contents-comment-text">';
output += '<p>' + res.commentDTOList[i].commentContents + '</p>';
output += '</div>';
output += '<p class="detail-contents-comment-time">'
output += moment(res.commentDTOList[i].commentCreatedDate).format("YYYY-MM-DD HH:mm:ss");
output += '</p>';
output += '</div>';
}
여기까지가 페이징된 Lit의 정보를 양식에 맞춰
for문을 사용해 output변수에 문자열로 담아준 모습입니다.
for (let i = res.DetailCommentPage.startPage; i <= res.DetailCommentPage.endPage; i++) {
if (res.DetailCommentPage.page == i) {
numPut += '<a class="detail-contents-comment-paging-btn-off">' + i + '</a>';
} else {
numPut += '<a onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + i + ')" class="detail-contents-comment-paging-btn-on" style="cursor: pointer">' + i + '</a>';
}
}
여기까지가 페이징 처리된 dto의 정보를 for문을 사용해 담아준 모습입니다.
숫자 버튼의 정보입니다.
if (res.DetailCommentPage.page <= 1) {
commentPageDResult.innerHTML = "";
} else if (res.DetailCommentPage.page > res.DetailCommentPage.startPage) {
commentPageDResult.innerHTML = downPut;
}
"이전"페이지 버튼은 특정 상황에서는 화면에서 보이지 않아야하기 때문에
if문을 사용하여 특정 상황일때 비워줍니다.
if (res.DetailCommentPage.page == res.DetailCommentPage.maxPage) {
commentPageUResult.innerHTML = "";
} else {
commentPageUResult.innerHTML = upPut;
}
"다음"페이지 버튼의 특정 상황에서는 화면에서 보이지 않아야하기 때문에
if문을 사용하여 특정 상황일때 비워줍니다.
commentNumPageOn.innerHTML = numPut;
commentResult.innerHTML = output;
위에서 변수에 담아준 변수들을 각각의 부모태그를 담은 변수의
innerHTML에 담아줍니다.
},
error: function () {
console.log("실패");
}
}
)
};
- Controller
코멘트를 저장할때 사용하는 ajax의 PostMapping
@PostMapping("/comment/save")
public ResponseEntity<Map<String, Object>> commentSave(@RequestParam(value = "DetailPage", required = false, defaultValue = "1") int DetailPage,
@RequestParam(value = "q",required = false,defaultValue = "") String q,
@ModelAttribute CommentDTO commentDTO) {
page정보를 파라미터로 받습니다.
q는 받을 필요가 없는데 왜 받았을까요
사용자가 작성한 comment 정보를 dto로 바로 담아줍니다.
commentService.commentSave(commentDTO);
받아온 comment 정보를 저장합니다.
PageDTO DetailPageDTO = new PageDTO();
DetailPageDTO.setPage(DetailPage);
DetailPageDTO.setBoardId(commentDTO.getBoardId());
사용자가 입력한 댓글로 인해 페이지가 늘어났기 때문에
새로운 페이징 처리를 진행합니다.
List<CommentDTO> commentDTOList = commentService.commentList(DetailPageDTO);
페이징 처리된 List의 정보를 받아옵니다.
String count = commentService.commentCount(commentDTO.getBoardId());
몇개의 comment가 달렸는지 화면에 표시해야하기 때문에
comment의 count를 받아줍니다.
Map<String, Object> commentResponse = new HashMap<>();
commentResponse.put("comments", commentDTOList);
commentResponse.put("count", count);
commentResponse.put("boardDTO",boardService.findByBoard(commentDTO.getBoardId()));
질문 작성자를 판단해야하기 때문에 board의 정보를 받아줍니다.
commentResponse.put("DetailCommentPage",commentService.commentPagingParam(DetailPageDTO,q));
페이징 처리된 하단의 number정보를 받아줍니다.
return은 하나만 가능하기 때문에 Map으로 압축하여 return합니다.
return new ResponseEntity<>(commentResponse, HttpStatus.OK);
}
사용자가 페이지를 이동하는 경우 사용되는 PostMapping입니다.
@PostMapping("/comment/UDPage")
public ResponseEntity commentBackPage(@RequestParam(value = "DetailPage", required = false, defaultValue = "1") int DetailPage,
@RequestParam(value = "q",required = false,defaultValue = "") String q,
@RequestParam("boardId") Long boardId){
사용자가 요청한 page번호를 받아옵니다.
q는 여기 또썻네요 필요 없습니다.
요청한 board의 ID를 받아옵니다.
PageDTO DetailPageDTO = new PageDTO();
DetailPageDTO.setPage(DetailPage);
DetailPageDTO.setBoardId(boardId);
페이징 처리를 위해 받아온 정보를 PageDTO에 담아줍니다.
Map<String, Object> commentResponse = new HashMap<>();
정보 압축을 위한 Map선언입니다.
commentResponse.put("boardDTO",boardService.findByBoard(boardId));
사용자가 보고있는 게시판의 정보를 담아줍니다.
commentResponse.put("commentDTOList",commentService.commentList(DetailPageDTO));
사용자가 요청한 해당 페이지의 List를 담아줍니다.
commentResponse.put("DetailCommentPage",commentService.commentPagingParam(DetailPageDTO,q));
페이지를 이동했기 때문에 새로운 페이징 정보를 담아줍니다.
DB를 통해 받아온 정보를 하나로 압축하여 RETURN 합니다.
return new ResponseEntity<>(commentResponse,HttpStatus.OK);
}
}
'나의 수업일지' 카테고리의 다른 글
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (11) - 프로젝트 마무리 (0) | 2023.06.13 |
---|---|
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (10) (0) | 2023.06.12 |
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (8) (0) | 2023.06.11 |
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (7) (0) | 2023.06.11 |
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (6) (0) | 2023.06.09 |
- 네이버 지식인 게시글 상세페이지 댓글


맨 처음 댓글을 만들때 전에 했던대로 하면된다고 생각했지만
글작성자의 경우 질문 작성자로 사용자의 이름이 작성되어야하고
당연히 일정이상의 댓글이 달리는 경우 페이징까지 진행해야했습니다.
또한 댓글공간을 윈도우로드를 사용하였기 때문에 페이지가 넘어가면 새로고침되며
디스플레이가 none으로 바뀌는 상황으로 ajax를 사용해 비동기 처리를 진행해야 했습니다.
- boardDetail.jsp - 코멘트 작성 공간
게시글 상세페이지의 댓글 작성을 진행하는 공간입니다
로그인을 하지 않은경우 코멘트를 작성하는 공간을 클릭하면
로그인이 필요하다는 문구를 confirm을 사용하여 확인 취소를 받고
확인을 클릭하는 경우 로그인 페이지를 화면에 띄웁니다.
<div class="detail-contents-comment-box">
<fieldset style="border: 0;">
<div class="detail-contents-comment-inner">
<c:choose>
<c:when test="${memberDTO != null}">
<textarea class="detail-contents-comment-textarea" maxlength="1000"
id="detail-contents-comment-textarea"
placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."></textarea>
</c:when>
<c:otherwise>
<textarea class="detail-contents-comment-textarea" maxlength="1000"
id="detail-contents-comment-textarea"
placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."
onclick="plzLogin()"></textarea>
</c:otherwise>
</c:choose>
</div>
<div class="detail-contents-comment-textarea-bottom">
<c:choose>
<c:when test="${sessionScope.memberId != null}">
<button type="button" class="detail-contents-comment-textarea-btn"
id="bestbtn" style="cursor: pointer;"
onclick="commentSave(${BoardDTO.id},${BoardDTO.memberId})">
등록
</button>
</c:when>
<c:otherwise>
<button type="button" class="detail-contents-comment-textarea-btn"
id="notlogin" style="cursor: pointer;"
onclick="plzLogin()">등록
</button>
</c:otherwise>
</c:choose>
</div>
</fieldset>
</div>
- boardDetail.jsp - 댓글 List 공간
commentList의 페이징 List를 출력하는 공간
forEach문을 돌리면서 게시글의 memberId와 comment의 memberId가 같은경우
작성자의 이름을 질문 작성자로 변경합니다.
<span class="detail-contents-comment-list-box" id="detail-contents-comment-list-box">
<c:forEach items="${CommentList}" var="CommentList">
<div class="detail-contents-comment-list">
<p class="detail-contents-comment-title">
<c:choose>
<c:when test="${CommentList.memberId == BoardDTO.memberId}">
<strong>질문 작성자</strong>
</c:when>
<c:otherwise>
<strong>${CommentList.commentWriter}</strong>
</c:otherwise>
</c:choose>
</p>
<div class="detail-contents-comment-text">
${CommentList.commentContents}
</div>
<p class="detail-contents-comment-time">
<fmt:formatDate value="${CommentList.commentCreatedDate}"
pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
</p>
</div>
</c:forEach>
</span>
<div class="detail-contents-comment-paging">
<span id="detail-contents-comment-paging-bbtn-on"></span>
<div style="display: inline-block;" id="numResult">
<c:forEach begin="${CommentPaging.startPage}" end="${CommentPaging.endPage}" var="i"
step="1">
<c:choose>
<c:when test="${i eq CommentPaging.page}">
<a class="detail-contents-comment-paging-btn-off">${i}</a>
</c:when>
<c:otherwise>
<a onclick="commentNBBtn(${BoardDTO.id},${BoardDTO.memberId},${i})"
class="detail-contents-comment-paging-btn-on"
style="cursor: pointer">${i}</a>
</c:otherwise>
</c:choose>
<%--href="/board/detail?BoardId=${BoardDTO.id}&DetailPage=${i}"--%>
</c:forEach>
</div>
<span id="detail-contents-comment-paging-nbtn-on">
<c:choose>
<c:when test="${CommentPaging.maxPage <= 1}">
</c:when>
<c:otherwise>
<c:if test="${CommentPaging.page != CommentPaging.maxPage}">
<a class="detail-contents-comment-paging-nbtn-on"
onclick="commentNBBtn(${BoardDTO.id},${BoardDTO.memberId},${CommentPaging.page+1})"
style="cursor: pointer;">
<span>다음</span>
<i class="comment-next-icon"></i>
</a>
</c:if>
</c:otherwise>
</c:choose>
</span>
</div>
- boardDetail.jsp - script
댓글 공간을 보여주기 위한 함수
시작은 display none 이고 클릭하면 block 으로 바뀌며 보여짐
window.onload를 사용한 이유는 처음 시작에 두번 클릭해야하는 오류를
고치지 못했기 때문에 어쩔수 없이 사용함
window.onload = function () {
const openComment = document.getElementById('openComment');
const commentBox = document.getElementById('detail-contents-comment-area');
openComment.addEventListener("click", function () {
if (commentBox.style.display === "block") {
commentBox.style.display = "none";
} else {
commentBox.style.display = "block";
}
})
layout을 보여주기 위한 함수
시작은 댓글과 마찬가지로 display none이고
똑같이 두번 클릭해야하는 오류를 수정하지 못해 window onload를 사용함
const layoutController = document.getElementById('layout-controller');
const layoutBox = document.getElementById('layout-box');
layoutController.addEventListener("click", function () {
if (layoutBox.style.display === "block") {
layoutBox.style.display = "none";
} else {
layoutBox.style.display = "block";
}
})
}
댓글 작성에 사용된 함수
등록을 하면 바로 반영된 모습을 보여주기 위해
ajax를 사용하여 비동기 처리함
const commentSave = (boardid, boardMemberid) => {
댓글을 작성한 게시판의 id , 게시글을 작성한 사용자의 id를 매개변수로 받음
const commentWriter = '${memberDTO.memberEmail}';
댓글을 작성한 사용자의 email을 담은 변수
const commentContents = document.getElementById('detail-contents-comment-textarea').value;
댓글을 작성하는 textarea의 vlue를 가져오는 document 객체
const boardId = boardid;
댓글이 달린 게시판의 id를 담은 변수
const memberId = '${sessionScope.memberId}';
댓글을 작성한 사용자의 id
const commentResult = document.getElementById('detail-contents-comment-list-box');
페이징처리를 진행하고 받아온 List를 출력해줄 공간의 document 객체
const boardMemberId = boardMemberid;
게시판 작성자의 id를 담은 변수
const countResult = document.getElementById('detail-contents-comment-count');
댓글이 몇개 달렸는지 출력하는 태그의 document 객체
const commentPageDResult = document.getElementById('detail-contents-comment-paging-bbtn-on');
페이징의 "이전"버튼을 담고있는 태그의 document 객체
const commentPageUResult = document.getElementById('detail-contents-comment-paging-nbtn-on');
페이징의 "다음"버튼을 담고있는 태그의 document 객체
const commentNumPageOn = document.getElementById('numResult');
페이징의 숫자 버튼을 담고있는 태그의 document 객체
$.ajax({
type: "post",
url: "/comment/save",
data: {
"commentWriter": commentWriter,
"commentContents": commentContents,
"boardId": boardId,
"memberId": memberId
사용자가 작성한 댓글을 서버로 보내 저장후
비동기처리로 바로 반영된 모습을 보여줍니다.
},
success: function (res) {
let output = "";
페이징 처리된 List를 담아줄 output 변수
let commentCount = res.count;
댓글의 count를 담아주는 conmmentCount 변수
let downPut = "";
"이전"버튼을 담아줄 downPut 변수
let upPut = "";
"다음"버튼을 담아줄 upPut 변수
let numPut = "";
페이징된 숫자버튼을 담아줄 numPut 변수
downPut += '<a class="detail-contents-comment-paging-bbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page - 1) + ')" style="cursor: pointer;">' +
'<i class="comment-back-icon"></i>' + '<span> 이전</span>' + '</a>';
upPut += '<a class="detail-contents-comment-paging-nbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page + 1) + ')" style="cursor: pointer;">' + '<span>다음 </span>' + '<i class="comment-next-icon"></i>' + '</a>';
"다음" / "이전" 버튼을 문자열로 양식에 맞게 담아줍니다.
for (let i in res.comments) {
output += '<div class="detail-contents-comment-list">';
output += '<p class="detail-contents-comment-title">';
if (res.comments[i].memberId == boardMemberId) {
output += '<strong>질문 작성자</strong>';
} else {
output += '<strong>' + res.comments[i].commentWriter + '</strong>';
}
output += '</p>';
output += '<div class="detail-contents-comment-text">';
output += '<p>' + res.comments[i].commentContents + '</p>';
output += '</div>';
output += '<p class="detail-contents-comment-time">'
output += moment(res.comments[i].commentCreatedDate).format("YYYY-MM-DD HH:mm:ss");
output += '</p>';
output += '</div>';
}
여기까지가 코멘트 List의 정보를 for문을 사용하여
output에 문자열로 담아준 모습입니다.
for (let i = res.DetailCommentPage.startPage; i <= res.DetailCommentPage.endPage; i++) {
if (res.DetailCommentPage.page == i) {
numPut += '<a class="detail-contents-comment-paging-btn-off">' + i + '</a>';
} else {
numPut += '<a onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + i + ')" class="detail-contents-comment-paging-btn-on" style="cursor: pointer">' + i + '</a>';
}
}
여기까지가 페이징 처리가된 dto의 정보를
for문을 사용하여 numPut에 담아준 모습입니다.
if (res.DetailCommentPage.page <= 1) {
commentPageDResult.innerHTML = "";
} else if (res.DetailCommentPage.page > res.DetailCommentPage.startPage) {
commentPageDResult.innerHTML = downPut;
}
"이전"페이지 버튼의 경우 특정 상황에서는 보여지지 않아야하기 때문에
if문을 사용하여 paging된 정보와 비교하여 담아줍니다.
if (res.DetailCommentPage.page == res.DetailCommentPage.maxPage) {
commentPageUResult.innerHTML = "";
} else {
commentPageUResult.innerHTML = upPut;
}
"다음"페이지 버튼의 경우 특정 상황에서는 보여지지 않아야하기 때문에
if문을 사용하여 paging된 정보와 비교하여 담아줍니다.
commentNumPageOn.innerHTML = numPut;
countResult.innerHTML = commentCount;
commentResult.innerHTML = output;
document.getElementById('detail-contents-comment-textarea').value = "";
위에서 변수에 문자열로 담은 정보들을 각각의 위치의의 태그에
innerHTML을 사용하여 담아줍니다.
이후 댓글 작성 공간을 비워줍니다.
},
error: function () {
console.log("실패");
}
})
};
비로그인 상태에서 댓글 남기기를 시도하는 경우
로그인 후 이용하실 수 있다는 CONFIRM을 띄웁니다.
확인을 누르는 경우 로그인 페이지로 이동합니다.
const plzLogin = () => {
if (confirm("로그인 후 이용하실 수 있습니다.")) {
location.href = "/member/login";
}
}
코멘트List에서 페이지 이동을 시도한는 경우 사용되는 함수
const commentNBBtn = (boardid, boardMemberid, CommentPagingPage) => {
const DetailPage = CommentPagingPage;
사용자가 원하는 페이지의 정보를 담은 변수
const boardId = boardid;
해당 게시물의 id를 담은 변수
const boardMemberId = boardMemberid;
로그인된 사용자의 id를 담은 변수
const commentResult = document.getElementById('detail-contents-comment-list-box');
페이징 처리된 정보를 출력해주는 공간의 document객체를 담은 변수
const commentPageDResult = document.getElementById('detail-contents-comment-paging-bbtn-on');
"이전"페이지 버튼의 부모태그를 담은 document 객체를 담은 변수
const commentPageUResult = document.getElementById('detail-contents-comment-paging-nbtn-on');
"다음"페이지 버튼의 부모태그를 담은 document 객체를 담은 변수
const commentNumPageOn = document.getElementById('numResult');
페이징처리된 dto의 정보를 출력해줄 부모태그의 document 객체
$.ajax({
type: "post",
url: "/comment/UDPage",
data: {
"boardId": boardId,
"DetailPage": DetailPage,
},
success: function (res) {
let output = "";
페이징 처리된 List를 담아줄 output변수
let downPut = "";
"이전"페이지 버튼을 담아줄 downput 변수
let upPut = "";
"다음"페이지 버튼을 담아줄 upPut 변수
let numPut = "";
페이징된 dto정보를 담아줄 numPut 변수
downPut += '<a class="detail-contents-comment-paging-bbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page - 1) + ')" style="cursor: pointer;">' +
'<i class="comment-back-icon"></i>' + '<span> 이전</span>' + '</a>';
upPut += '<a class="detail-contents-comment-paging-nbtn-on" onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + (res.DetailCommentPage.page + 1) + ')" style="cursor: pointer;">' + '<span>다음 </span>' + '<i class="comment-next-icon"></i>' + '</a>';
"이전" / "다음" 버튼의 양식을 문자열로 각 변수에 담아줍니다.
for (let i in res.commentDTOList) {
output += '<div class="detail-contents-comment-list">';
output += '<p class="detail-contents-comment-title">';
if (res.commentDTOList[i].memberId == boardMemberId) {
output += '<strong>질문 작성자</strong>';
} else {
output += '<strong>' + res.commentDTOList[i].commentWriter + '</strong>';
}
output += '</p>';
output += '<div class="detail-contents-comment-text">';
output += '<p>' + res.commentDTOList[i].commentContents + '</p>';
output += '</div>';
output += '<p class="detail-contents-comment-time">'
output += moment(res.commentDTOList[i].commentCreatedDate).format("YYYY-MM-DD HH:mm:ss");
output += '</p>';
output += '</div>';
}
여기까지가 페이징된 Lit의 정보를 양식에 맞춰
for문을 사용해 output변수에 문자열로 담아준 모습입니다.
for (let i = res.DetailCommentPage.startPage; i <= res.DetailCommentPage.endPage; i++) {
if (res.DetailCommentPage.page == i) {
numPut += '<a class="detail-contents-comment-paging-btn-off">' + i + '</a>';
} else {
numPut += '<a onclick="commentNBBtn(' + res.boardDTO.id + ',' + res.boardDTO.memberId + ',' + i + ')" class="detail-contents-comment-paging-btn-on" style="cursor: pointer">' + i + '</a>';
}
}
여기까지가 페이징 처리된 dto의 정보를 for문을 사용해 담아준 모습입니다.
숫자 버튼의 정보입니다.
if (res.DetailCommentPage.page <= 1) {
commentPageDResult.innerHTML = "";
} else if (res.DetailCommentPage.page > res.DetailCommentPage.startPage) {
commentPageDResult.innerHTML = downPut;
}
"이전"페이지 버튼은 특정 상황에서는 화면에서 보이지 않아야하기 때문에
if문을 사용하여 특정 상황일때 비워줍니다.
if (res.DetailCommentPage.page == res.DetailCommentPage.maxPage) {
commentPageUResult.innerHTML = "";
} else {
commentPageUResult.innerHTML = upPut;
}
"다음"페이지 버튼의 특정 상황에서는 화면에서 보이지 않아야하기 때문에
if문을 사용하여 특정 상황일때 비워줍니다.
commentNumPageOn.innerHTML = numPut;
commentResult.innerHTML = output;
위에서 변수에 담아준 변수들을 각각의 부모태그를 담은 변수의
innerHTML에 담아줍니다.
},
error: function () {
console.log("실패");
}
}
)
};
- Controller
코멘트를 저장할때 사용하는 ajax의 PostMapping
@PostMapping("/comment/save")
public ResponseEntity<Map<String, Object>> commentSave(@RequestParam(value = "DetailPage", required = false, defaultValue = "1") int DetailPage,
@RequestParam(value = "q",required = false,defaultValue = "") String q,
@ModelAttribute CommentDTO commentDTO) {
page정보를 파라미터로 받습니다.
q는 받을 필요가 없는데 왜 받았을까요
사용자가 작성한 comment 정보를 dto로 바로 담아줍니다.
commentService.commentSave(commentDTO);
받아온 comment 정보를 저장합니다.
PageDTO DetailPageDTO = new PageDTO();
DetailPageDTO.setPage(DetailPage);
DetailPageDTO.setBoardId(commentDTO.getBoardId());
사용자가 입력한 댓글로 인해 페이지가 늘어났기 때문에
새로운 페이징 처리를 진행합니다.
List<CommentDTO> commentDTOList = commentService.commentList(DetailPageDTO);
페이징 처리된 List의 정보를 받아옵니다.
String count = commentService.commentCount(commentDTO.getBoardId());
몇개의 comment가 달렸는지 화면에 표시해야하기 때문에
comment의 count를 받아줍니다.
Map<String, Object> commentResponse = new HashMap<>();
commentResponse.put("comments", commentDTOList);
commentResponse.put("count", count);
commentResponse.put("boardDTO",boardService.findByBoard(commentDTO.getBoardId()));
질문 작성자를 판단해야하기 때문에 board의 정보를 받아줍니다.
commentResponse.put("DetailCommentPage",commentService.commentPagingParam(DetailPageDTO,q));
페이징 처리된 하단의 number정보를 받아줍니다.
return은 하나만 가능하기 때문에 Map으로 압축하여 return합니다.
return new ResponseEntity<>(commentResponse, HttpStatus.OK);
}
사용자가 페이지를 이동하는 경우 사용되는 PostMapping입니다.
@PostMapping("/comment/UDPage")
public ResponseEntity commentBackPage(@RequestParam(value = "DetailPage", required = false, defaultValue = "1") int DetailPage,
@RequestParam(value = "q",required = false,defaultValue = "") String q,
@RequestParam("boardId") Long boardId){
사용자가 요청한 page번호를 받아옵니다.
q는 여기 또썻네요 필요 없습니다.
요청한 board의 ID를 받아옵니다.
PageDTO DetailPageDTO = new PageDTO();
DetailPageDTO.setPage(DetailPage);
DetailPageDTO.setBoardId(boardId);
페이징 처리를 위해 받아온 정보를 PageDTO에 담아줍니다.
Map<String, Object> commentResponse = new HashMap<>();
정보 압축을 위한 Map선언입니다.
commentResponse.put("boardDTO",boardService.findByBoard(boardId));
사용자가 보고있는 게시판의 정보를 담아줍니다.
commentResponse.put("commentDTOList",commentService.commentList(DetailPageDTO));
사용자가 요청한 해당 페이지의 List를 담아줍니다.
commentResponse.put("DetailCommentPage",commentService.commentPagingParam(DetailPageDTO,q));
페이지를 이동했기 때문에 새로운 페이징 정보를 담아줍니다.
DB를 통해 받아온 정보를 하나로 압축하여 RETURN 합니다.
return new ResponseEntity<>(commentResponse,HttpStatus.OK);
}
}
'나의 수업일지' 카테고리의 다른 글
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (11) - 프로젝트 마무리 (0) | 2023.06.13 |
---|---|
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (10) (0) | 2023.06.12 |
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (8) (0) | 2023.06.11 |
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (7) (0) | 2023.06.11 |
인천 일보 아카데미 58~67일 차 개인 프로젝트 - NAVER 지식in 클론 코딩 (6) (0) | 2023.06.09 |