댓글 목록 조회
// 댓글 목록 조회(AJAX)
function selectReplyList(){
// contextPath, boardNo, memberNo 전역변수 사용
$.ajax({
url : contextPath + "/reply/selectReplyList",
data : {"boardNo" : boardNo},
type : "get",
dataType : "JSON", // JSON 형태의 문자열 응답 데이터를 JS 객체로 자동 변환
success : function(rList){
// rList : 반환받은 댓글 목록
console.log(rList);
// 화면에 출력되어 있는 댓글 목록 삭제
const replyList = document.getElementById("reply-list"); // ul 태그
replyList.innerHTML="";
// rList에 저장된 요소를 하나씩 접근
for(let reply of rList){
// 행
const replyRow = document.createElement("li");
replyRow.classList.add("reply-row");
// 작성자
const replyWriter = document.createElement("p");
replyWriter.classList.add("reply-writer");
// 프로필 이미지
const profileImage = document.createElement("img");
if(reply.profileImage != null){ // 프로필 이미지가 있는 경우
profileImage.setAttribute("src", contextPath + reply.profileImage);
} else { // 없는 경우 == 기본 이미지
profileImage.setAttribute("src", contextPath + "/resources/images/user.png");
}
// 작성자 닉네임
const memberNickname = document.createElement("span");
memberNickname.innerText = reply.memberNickname;
// 작성일
const replyDate = document.createElement("span");
replyDate.classList.add("reply-date");
replyDate.innerText = "(" + reply.createDate + ")";
// 작성자 영역(p)에 프로필, 닉네임, 작성일을 마지막 자식으로 추가
replyWriter.append(profileImage, memberNickname, replyDate);
// 댓글 내용
const replyContent = document.createElement("p");
replyContent.classList.add("reply-content");
// 왜 innerHTML? <br> 태그 인식을 위해서
replyContent.innerHTML = reply.replyContent;
// 행에 작성자, 내용 추가
replyRow.append(replyWriter, replyContent);
// 로그인한 회원 번호와 댓글 작성자의 회원번호가 같을 때만 버튼 추가
if(loginMemberNo == reply.memberNo){
// 버튼 영역
const replyBtnArea = document.createElement("div");
replyBtnArea.classList.add("reply-btn-area");
// 수정 버튼
const updateBtn = document.createElement("button");
updateBtn.innerText="수정";
// 수정 버튼에 onclick 이벤트 속성 추가
updateBtn.setAttribute("onclick", "showUpdateReply(" + reply.replyNo + ", this)");
// 삭제 버튼
const deleteBtn = document.createElement("button");
deleteBtn.innerText="삭제";
// 삭제 버튼에 onclick 이벤트 속성 추가
deleteBtn.setAttribute("onclick", "deleteReply("+ reply.replyNo +")")
// 버튼 영역 마지막 자식으로 수정/삭제 버튼 추가
replyBtnArea.append(updateBtn, deleteBtn);
// 행에 버튼 영역 추가
replyRow.append(replyBtnArea);
}
// 댓글 목록(ul)에 행(li)추가
replyList.append(replyRow);
}
},
error : function(){
console.log("오류발생");
}
});
}
@WebServlet("/reply/*") // reply로 시작하는 모든 요청 받음
public class ReplyController extends HttpServlet {
// /reply/selectReplyList
// /reply/insert
// /reply/update
// /reply/delete
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// GET 방식 요청 처리
String uri = req.getRequestURI();
// /community/reply/insert
String contextPath = req.getContextPath();
// /community
String command = uri.substring( (contextPath + "/reply/").length() );
// insert
ReplyService service = new ReplyService();
try {
// 댓글 목록 조회 요청인 경우
if(command.equals("selectReplyList")) {
// 파라미터를 얻어와 정수 형태로 파싱
int boardNo = Integer.parseInt(req.getParameter("boardNo"));
// 댓글 목록 조회 service 호출 후 결과 반환 받기
List<Reply> replyList =service.selectReplyList(boardNo);
// JSON 변환 + 응답
new Gson().toJson(replyList, resp.getWriter());
}
/** 댓글 목록 조회 service
* @param boardNo
* @return replyList
* @throws Exception
*/
public List<Reply> selectReplyList(int boardNo) throws Exception{
Connection conn = getConnection();
List<Reply> replyList = dao.selectReplyList(conn, boardNo);
close(conn);
return replyList;
}
/** 댓글 목록 조회 DAO
* @param conn
* @param boardNo
* @return replyList
* @throws Exception
*/
public List<Reply> selectReplyList(Connection conn, int boardNo) throws Exception {
List<Reply> replyList = new ArrayList<Reply>();
try {
String sql = prop.getProperty("selectReplyList");
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, boardNo);
rs = pstmt.executeQuery();
while(rs.next()) {
Reply r = new Reply();
r.setReplyNo(rs.getInt("REPLY_NO"));
r.setReplyContent(rs.getString(2));
r.setCreateDate(rs.getString(3));
r.setBoardNo(rs.getInt(4));
r.setMemberNo(rs.getInt(5));
r.setMemberNickname(rs.getString(6));
r.setProfileImage(rs.getString(7));
replyList.add(r);
}
} finally {
close(rs);
close(pstmt);
}
return replyList;
}
<!-- 댓글 목록 조회 -->
<entry key="selectReplyList">
SELECT REPLY_NO, REPLY_CONTENT,
TO_CHAR(CREATE_DT, 'YYYY.MM.DD HH24:MI:SS') CREATE_DT,
BOARD_NO, MEMBER_NO, MEMBER_NICK, PROFILE_IMG
FROM REPLY
JOIN MEMBER USING(MEMBER_NO)
WHERE REPLY_ST ='N'
AND BOARD_NO=?
ORDER BY REPLY_NO
</entry>
<div class="reply-list-area">
<ul id="reply-list">
<c:forEach var="reply" items="${rList}">
<li class="reply-row">
<p class="reply-writer">
<c:if test="${empty reply.profileImage}">
<!-- 프로필 이미지가 없을 경우 -->
<img src="${contextPath}/resources/images/user.png">
</c:if>
<c:if test="${!empty reply.profileImage}">
<!-- 프로필 이미지가 있을 경우 -->
<img src="${contextPath}${reply.profileImage}">
</c:if>
<span>${reply.memberNickname}</span>
<span class="reply-date"> (${reply.createDate})</span>
</p>
<p class="reply-content">${reply.replyContent}</p>
<c:if test="${loginMember.memberNo == reply.memberNo}">
<div class="reply-btn-area">
<button onclick="showUpdateReply(${reply.replyNo}, this)">수정</button>
<button onclick="deleteReply(${reply.replyNo})">삭제</button>
</div>
</c:if>
</li>
</c:forEach>
</ul>
</div>