프로젝트

15. 공지사항 게시판 (댓글 등록)

하차모 2023. 5. 26. 00:36

+) 댓글 테이블에 댓글 작성자 컬럼 추가함 (까먹음..)

댓글 작성자 컬럼은 사원 테이블의 사원 번호 컬럼을 참조하는 외래키임.

ALTER TABLE BOARD_REPLY ADD REPLY_WRITER NUMBER CONSTRAINT REPLY_EMP_FK REFERENCES EMP(EMPNO) NOT NULL;

 

 

댓글 등록

글 상세 조회 페이지 하단에 댓글 테이블을 만들었다.

제일 하단에 댓글 입력 칸이 있고 시간순으로 위에서 아래로 댓글이 등록되도록 했음

 

 

(댓글 입력 칸)

등록 버튼을 클릭하면 regReply() 함수가 실행됨

notice_detail.html

<tr class="border-top" id="regReplyTr">
	<td colspan="2">
		<div class="input-group">
			<textarea class="form-control" rows="5px" style="resize: none" id="replyTextarea"></textarea>
			<input type="button" class="btn" th:onclick="regReply([[${notice.boardNum}]]);" value="등록">
		</div>
	</td>
</tr>

 

 

regReply() 함수

댓글 기능은 전체적으로 Ajax로 구현했는데, 페이지 리로딩 없이 비동기식으로 처리할 수 있기 때문이다.

notice_detail.js

//댓글 등록
function regReply(boardNum) {
	const replyTextarea = document.querySelector('#replyTextarea');
	const replyContent = replyTextarea.value;
	const regReplyTr = document.querySelector('#regReplyTr');
	const noReplyTr = document.querySelector('#noReplyTr');
	const replyCntSpan = document.querySelector('#replyCntSpan');
	
	if(replyContent == '' || replyContent == null) {
		alert('댓글을 입력해주세요.');
		return false;
	};
	
	const replyContentBr = replyContent.replace(/(?:\\r\\n|\\r|\\n)/g, '<br>');
	
	//ajax start
	$.ajax({
		url: '/reply/regReply', //요청경로
		type: 'post',
		async: true,
		contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
		data: {'replyContent' : replyContentBr, 'boardNum' : boardNum}, //필요한 데이터
		success: function(result) {
			const reply = result;
			
			if(noReplyTr != null) {
				noReplyTr.remove();
			}
			
			let str = '';
			
			str += `<tr class="border-top">                                                         `;
			str += `	<td class="text-center">                                                    `;
			str += `		<img src="/img/content/board/testProfile.png" width="100%" class="mx-0">`;
			str += `	</td>                                                                       `;
			str += `	<td>                                                                        `;
			str += `		<div class="d-flex justify-content-between">                            `;
			str += `			<div class="fw-semibold mb-1">${reply.ename}</div>                    `;
			str += `			<div class="text-secondary fs-6">${reply.replyDate}</div>           `;
			str += `		</div>                                                                  `;
			str += `		<div>${reply.replyContent}</div>                                              `;
			str += `		<div class="d-grid gap-1 d-md-flex justify-content-md-end">             `;
			str += `			<input type="button" class="btn" onclick="updateReplyForm('${reply.replyNum}', this)" value="수정">                      `;
			str += `			<input type="button" class="btn" onclick="deleteReply('${reply.replyNum}', this)" value="삭제">                      `;
			str += `		</div>                                                                  `;
			str += `	</td>                                                                       `;
			str += `</tr>                                                                           `;
			
			
			regReplyTr.insertAdjacentHTML('beforebegin', str);
			
			replyTextarea.value = '';
			
			replyCntSpan.textContent = Number(replyCntSpan.textContent) + 1;
		},
		error: function() {
			alert('실패');
		}
	});
	//ajax end
	
}

textarea value 값이 비어 있을 때 간단한 유효성 검사와 정규식을 사용해 엔터값이 넘어 왔을 때 <br> 태그로 바꿔 주었다.

 

댓글 등록은 리소스 생성이기 때문에 POST 방식을 사용한다.

 

댓글 내용 값(replyContent)과 댓글을 등록하는 글의 번호(boardNum)를 넘겨준다.

 

 

noReplyTr은 위 사진처럼 댓글이 없을 때 보이는 tr태그이다.

지금 등록하는 댓글이 해당 글의 첫 댓글이라면 (=noReplyTr이 존재한다면) 그 tr을 삭제함

 

컨트롤러의 리턴 값이 새로 등록한 댓글을 ReplyVO이기 때문에 받아온 값으로 바로 댓글 테이블에 등록한 댓글 정보를 추가함

 

댓글 테이블 상단에 현재 글의 댓글 수가 몇개인지가 나타나 있는데 , 해당 span태그도 가져와서 1을 더해준 값으로 바꿔준다.

 

++) 아직 로그인 처리를 안 해서 댓글을 쓴 사람의 이미지, 이름 들고오는 작업도 해야 함

 

 

ReplyController.java

//댓글 등록
@ResponseBody
@PostMapping("/regReply")
public ReplyVO regReplyAjax(ReplyVO replyVO) {
    //다음으로 들어갈 댓글 번호 조회
    String nextReplyNum = replyService.getNextReplyNum();
    //댓글 번호 세팅
    replyVO.setReplyNum(nextReplyNum);

    //댓글 등록
    replyService.regReply(replyVO);

    return replyService.getReplyByReplyNum(nextReplyNum);
}

등록한 댓글을 바로 조회해서 반환해 주기 위해서(Ajax에서 받은 반환값으로 화면에 바로 댓글을 띄워줘야 하기 때문) 댓글 번호 조회를 따로 만듦

 

 

댓글 테이블 html

 

notice_detail.html

<div class="row">
	<div class="col-12 mb-1">
		<span id="replyCntSpan">[[${notice.replyCnt}]]</span>개의 댓글
	</div>
	<div class="col-12">
		<table class="table table-borderless border-top border-bottom" id="replyTable">
			<colgroup>
				<col width="5%">
				<col width="*">
			</colgroup>

			<th:block th:if="${#lists.size(notice.replyList) == 0}">
				<tr class="border-top" id="noReplyTr">
					<td class="text-secondary text-center align-middle" colspan="2" height="120px">
						등록된 댓글이 없습니다.
					</td>
				</tr>
			</th:block>
			<th:block th:if="${#lists.size(notice.replyList) != 0}"
						th:each="reply : ${notice.replyList}">
				<tr class="border-top">
					<td class="text-center">
						<img src="/img/content/board/testProfile.png" width="100%" class="mx-0">
					</td>
					<td>
						<div class="d-flex justify-content-between">
							<div class="fw-semibold mb-1">[[${reply.ename}]]</div>
							<div class="text-secondary fs-6">[[${reply.replyDate}]]</div>
						</div>
						<div th:utext="${reply.replyContent}"></div>
						<div class="d-grid gap-1 d-md-flex justify-content-md-end">
							<input type="button" class="btn" th:onclick="updateReplyForm([[${reply.replyNum}]], this)" value="수정">
							<input type="button" class="btn" th:onclick="deleteReply([[${reply.replyNum}]], this)" value="삭제">
						</div>
					</td>
				</tr>
			</th:block>

			<tr class="border-top" id="regReplyTr">
				<td colspan="2">
					<div class="input-group">
						<textarea class="form-control" rows="5px" style="resize: none" id="replyTextarea"></textarea>
						<input type="button" class="btn" th:onclick="regReply([[${notice.boardNum}]]);" value="등록">
					</div>
				</td>
			</tr>
		</table>
	</div>
</div>