📝 댓글 목록 조회 기능
💡 VS Code
🔎 boardDetail.jsp
...
<script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
<script src="${contextPath}/resources/js/board/board.js"></script>
<script>
const contextPath = "${contextPath}";
const boardNo = "${detail.boardNo}";
const loginMemberNo = "${loginMember.memberNo}";
</script>
<script src="${contextPath}/resources/js/board/reply.js"></script>
</body>
</html>
🔎 reply.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div id="reply-area">
<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>수정</button>
<button>삭제</button>
</div>
</c:if>
</li>
</c:forEach>
<li class="reply-row">
<p class="reply-writer">
<img src="${contextPath}/resources/images/user.png">
<span>댓글 작성자 닉네임</span>
<span class="reply-date"> (2023.07.20 10:20:30) </span>
</p>
<p class="reply-content">
댓글 내용입니다.<br>
이런식으로 출력 예정!
</p>
<div class="reply-btn-area">
<button>수정</button>
<button>삭제</button>
</div>
</li>
</ul>
</div>
<div class="reply-write-area">
<textarea id="replyContent"></textarea>
<button id="addReply">
댓글<br>
등록
</button>
</div>
</div>
🔎 reply-style.css
#reply-list{
padding: 0;
list-style: none;
}
.reply-row{
padding: 15px 30px;
border-top: 1px solid #ccc;
}
.reply-writer > img{
width: 40px;
height: 40px;
}
.reply-writer > span{
font-weight: bold;
margin-left: 10px;
}
.reply-date{
font-size: 0.8em;
color: #aaa;
}
.reply-btn-area{
display: flex;
justify-content: flex-end;
}
.reply-btn-area > button{
width: 50px;
height: 30px;
margin-left: 10px;
font-weight: bold;
color: white;
background-color: #455ba8;
border: 0;
border-radius: 3px;
cursor: pointer;
}
.reply-btn-area > button:hover{
background-color: white;
border: 2px solid #455ba8;
color: #455ba8;
}
.reply-write-area{
display: flex;
justify-content: center;
min-height: 85px;
margin: 30px 0;
}
#replyContent{
resize: none;
margin-right: 10px;
flex-basis: 75%;
}
#addReply{
flex-basis: 8%;
font-weight: bold;
background-color: #455ba8;
color: white;
border: 0;
cursor: pointer;
}
#addReply:hover{
background-color: white;
color: #455ba8;
border: 2px solid #455ba8;
}
🔎 reply.js
function selectReplyList(){
$.ajax({
url : contextPath + "/reply/selectReplyList",
data : {"boardNo" : boardNo},
type : "get",
dataType : "JSON",
success : function(rList){
console.log(rList);
const replyList = document.getElementById("reply-list");
replyList.innerHTML = "";
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 + ")";
replyWriter.append(profileImage, memberNickname, replyDate);
const replyContent = document.createElement("p");
replyContent.classList.add("reply-content");
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 = "수정";
const deleteBtn = document.createElement("button");
deleteBtn.innerText = "삭제";
replyBtnArea.append(updateBtn, deleteBtn);
replyRow.append(replyBtnArea);
}
replyList.append(replyRow);
}
},
error : function(){
console.log("에러 발생");
}
});
}
💡 Eclipse
🔎 boardDetailServlet.java
package edu.kh.community.board.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import edu.kh.community.board.model.service.BoardService;
import edu.kh.community.board.model.service.ReplyService;
import edu.kh.community.board.model.vo.BoardDetail;
import edu.kh.community.board.model.vo.Reply;
@WebServlet("/board/detail")
public class BoardDetailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
int boardNo = Integer.parseInt(req.getParameter("no"));
BoardService service = new BoardService();
BoardDetail detail = service.selectBoardDetail(boardNo);
if(detail != null) {
List<Reply> rList = new ReplyService().selectReplyList(boardNo);
req.setAttribute("rList", rList);
}
req.setAttribute("detail", detail);
String path = "/WEB-INF/views/board/boardDetail.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(path);
dispatcher.forward(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
🔎 ReplyController.java
package edu.kh.community.board.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import edu.kh.community.board.model.service.ReplyService;
import edu.kh.community.board.model.vo.Reply;
@WebServlet("/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();
String contextPath = req.getContextPath();
String command = uri.substring( (contextPath + "/reply/").length() );
ReplyService service = new ReplyService();
try {
// 댓글 목록 조회 요청인 경우
if(command.equals("selectReplyList")) {
// 파라미터를 얻어와 정수 형태로 파싱
int boardNo = Integer.parseInt(req.getParameter("boardNo"));
// 댓글 목록 조회 서비스 호출 후 결과 반환 받기
List<Reply> rList = service.selectReplyList(boardNo);
// JSON 변환 + 응답
new Gson().toJson(rList, resp.getWriter());
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// POST방식 요청 처리
doGet(req, resp); // POST로 전달된 요청을 doGet()으로 전달하여 수행
}
}
🔎 ReplyService.java
package edu.kh.community.board.model.service;
import static edu.kh.community.common.JDBCTemplate.*;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import edu.kh.community.board.model.dao.ReplyDAO;
import edu.kh.community.board.model.vo.Reply;
public class ReplyService {
private ReplyDAO dao = new ReplyDAO();
public List<Reply> selectReplyList(int boardNo) throws Exception {
Connection conn = getConnection();
List<Reply> rList = dao.selectReplyList(conn, boardNo);
close(conn);
return rList;
}
}
🔎 ReplyDAO.java
package edu.kh.community.board.model.dao;
import static edu.kh.community.common.JDBCTemplate.*;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import edu.kh.community.board.model.vo.Reply;
public class ReplyDAO {
private Statement stmt;
private PreparedStatement pstmt;
private ResultSet rs;
private Properties prop;
public ReplyDAO() {
try {
prop = new Properties();
String filePath = ReplyDAO.class.getResource("/edu/kh/community/sql/reply-sql.xml").getPath();
prop.loadFromXML(new FileInputStream(filePath));
} catch (Exception e) {
e.printStackTrace();
}
}
public List<Reply> selectReplyList(Connection conn, int boardNo) throws Exception {
List<Reply> rList = 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(1) );
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) );
rList.add(r);
}
} finally {
close(rs);
close(pstmt);
}
return rList;
}
}
🔎 reply-sql.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>reply-sql.xml</comment>
<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>
</properties>
소중한 정보 감사드립니다!