본문 바로가기
인천일보아카데미/- 학습일지

[학습일지]JAVA교육일지 게시판CRUD 6⭐ 댓글기능

by w1z 2022. 7. 20.

기본 게시판 만들기

  1. 댓글 목록보기

  2. 댓글 작성하기

  3. 댓글 삭제하기


1. 댓글 목록보기

[ 구현 목표 ]

- 댓글항목에는 댓글내용, 이름, 작성일자를 확인 할 수 있다.

- 해당 글에 댓글이 없다면 "댓글이 없습니다"를 출력한다.

 

[ SQl-Developer - DB 테이블 만들기 ]

- tblComment

-- 댓글 테이블 생성
create table tblComment (

    seq number primary key,                             -- 댓글번호(PK)
    id varchar2(30) not null references tblUsers(id),   -- 아이디(FK)
    content varchar2(2000) not null,                    -- 댓글내용
    regdate date default sysdate not null,              -- 작성날짜
    pseq number not null references tblBoards(seq)      -- 부모글번호(FK)

);

create sequence seqComment;


-- 댓글수를 위한 뷰 생성 (어제 만든것 수정 - ccnt 추가)
create or replace view vwBoard
as
    select 
        seq, id, 
        (select name from tblUsers where id = tblBoards.id) as name, 
        subject, 
        readcount, 
        regdate,
        (sysdate - regdate) as isnew,
        content,
        (select count(*) from tblComment where pseq = tblBoards.seq) as ccnt
    from tblBoards;

 

[ DB 작업 ]

1) com.test.myapp.board > CommentDTO.java

- tblComment 테이블의 컬럼값을 CommentDTO.java 파일에 각각 getter / setter를 만들어준다.

public class CommentDTO {
	
	private String seq;
	private String id;
	private String content;
	private String regdate;
	private String pseq;
	private String name; // 추가멤버 (이름) 


	// getter / setter 구현하기 (생략)
}

 

2) com.test.myapp.board > BoardDAO.java

- 글 내용 상세 페이지(View)에서 댓글 목록 출력을 위한 메소드

- 상세 페이지(부모 seq) <-> 댓글(자식 seq) 형식으로 쿼리문을 작성한다.

*어제 작성했던 파일 그대로 사용했으며, 어제 구현했던 코드는 일부 제거했습니다.

public ArrayList<CommentDTO> listComment(String seq) {
	
	try {
		
		// 부모글 번호를 조건으로 받기
		String sql = "select c.*, (select name from tblUsers where id = c.id) as name "
				+ "from tblComment c where pseq = ? order by seq asc";
		
		pstat = conn.prepareStatement(sql);
		pstat.setString(1, seq);
		
		rs = pstat.executeQuery();
		
		ArrayList<CommentDTO> clist = new ArrayList<CommentDTO>();
		
		while ( rs.next() ) {
			
			CommentDTO dto = new CommentDTO();
			
			dto.setSeq(rs.getString("seq"));
			dto.setContent(rs.getString("content"));
			dto.setId(rs.getString("id"));
			dto.setRegdate(rs.getString("regdate"));
			dto.setPseq(rs.getString("pseq"));
			dto.setName(rs.getString("name"));
			
			clist.add(dto);
			
		}
		
		return clist;
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return null;
}

 

[ Servlet + JSP 작업 ]

1) com.test.myapp.board > View.java

- 데이터 가져오기 ( seq )

- DB 작업

- BoardDTO 반환 > JSP 호출하기 + 전달하기

*어제 작성했던 파일 그대로 사용했으며, 어제 구현했던 코드는 일부 제거했습니다.

@WebServlet("/board/view.do")
public class View extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 1.
		String seq = req.getParameter("seq");
		
		// 2.
		BoardDAO dao = new BoardDAO();
		
		// 2.5 - 댓글 목록 가져오기
		ArrayList<CommentDTO> clist = dao.listComment(seq);
		
		// 3.
		req.setAttribute("clist", clist);

		RequestDispatcher dispatcher = req.getRequestDispatcher("/WEB-INF/views/board/view.jsp");
		dispatcher.forward(req, resp);

	}

}

 

2) WEB-INF > views > board > view.jsp

- 댓글이 아무것도 없을 경우 '댓글이 없습니다' 출력하기

- 댓글 항목에는 댓글내용, 이름, 작성일자가 표시된다.

- 버튼은 삭제하기 버튼만 존재한다.

<!-- css -->
<style>	
	#tblAddCommnet, #tblListComment { width: 700px; margin: 15px auto; }
	
	#tblAddComment { margin-top: 30px; }
	#tblAddComment td:nth-child(1) { width: 600px; }
	#tblAddComment td:nth-child(2) { width: 100px; }
	
	#tblListComment td:nth-child(1) { width: 600px; }
	#tblListComment td:nth-child(2) { width: 100px; }
	
	#tblListComment td {
		position: relative;
		left: 0;
		top: 0;
	}
	
	#tblListComment td span {
		position: absolute;
		right: 10px;
		bottom: 5px;
		color: #AAA;
		font-size: 11px;
	}
</style>
<!-- body -->
<div>

	<table id="tblListComment" class="table table-bordered">
		
		<c:if test="${ clist.size() == 0 }">
			<tr>
				<td colspan="2">댓글이 없습니다.</td>
			</tr>
		</c:if>
		
		<c:forEach items="${ clist }" var="cdto">
			<tr>
				<td>
					${ cdto.content }
					<span>${ cdto.name }. ${ cdto.regdate }</span>
				</td>
				<td>
					<input type="button" value="삭제하기" class="btn btn-default" 
						onclick="location.href='/myapp/board/delcomment.do?seq=${ cdto.seq }&pseq=${ dto.seq }';"/>
				</td>
			</tr>
		</c:forEach>	
	</table>
	
	<form method="POST" action="/myapp/board/addcomment.do">
		<table id="tblAddComment" class="table table-bordered">
			<tr>
				<td><input type="text" name="content" id="content" class="form-control" required placeholder="댓글을 작성하세요. "/></td>
				<td><input type="submit" value="댓글쓰기" class="btn btn-primary" /></td>
			</tr>
		</table>
		<input type="hidden" name="pseq" value="${ dto.seq }" />
	</form>
	
</div>

 

- 게시판 글 내용 상세 페이지 ( http://localhost:8090/myapp/board/view.do?seq=45 )

댓글 추가하기 기능을 아직 구현 하지않아서 현재는 빈 목록이다.

 

2. 댓글 작성하기

[ 구현 목표 ]

- 로그인한 사용자는 해당 글 상세 페이지 하단에서 댓글을 작성할 수 있다.

- 작성한 댓글내용, 작성일자, 이름을 확인할 수 있다.

- 게시판 리스트 페이지에서 댓글이 존재한다면 댓글 수를 확인할 수 있다.

 

[ DB 작업 ]

1) com.test.myapp.board > BoardDAO.java

- 댓글 작성할 수 있게 하는 메소드 구현한다.

public int addComment(CommentDTO dto) {
	
	try {
		
		String sql = "insert into tblComment (seq, id, content, regdate, pseq)"
				+ " values (seqBoards.nextVal, ?, ?, default, ?)";
		
		pstat = conn.prepareStatement(sql);
		
		pstat.setString(1, dto.getId());
		pstat.setString(2, dto.getContent());
		pstat.setString(3, dto.getPseq());
		
		return pstat.executeUpdate(); // 성공시 1 실패시 0
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return 0;
}

 

- 게시판 리스트(List)에 댓글수를 보여주기 위해 기존 list메소드에 ccnt 추가하기

- 기존의 BoardDTO.java에 ccnt 변수와 getter/setter 구현하기 (생략했습니다.) 

public ArrayList<BoardDTO> list(HashMap<String, String> map) {
	
	try {
		
		// 이 메소드의 집합
		// 1. 목록보기
		// 2. 검색하기
		
		String where ="";
		
		if ( map.get("isSearch").equals("y") ) {
			// 검색
			// where name like '%홍길동%'
			// where subject like '%날씨%'
			// where all like '%날씨%'
			
			if ( map.get("column").equals("all") ) {
				where = String.format(" where subject like '%%%s%%' or content like '%%%s%%' "
						, map.get("search"), map.get("search"));
			} else {
				where = String.format(" where %s like '%%%s%%' "
						, map.get("column"), map.get("search"));
			}
			
		}
		
		String sql = String.format("select * from vwBoard %s order by seq desc", where); 
		
		pstat = conn.prepareStatement(sql);
		
		rs = pstat.executeQuery();
		
		// 옮겨 담을 큰상자
		ArrayList<BoardDTO> list = new ArrayList<BoardDTO>();
				
		while ( rs.next() ) {
			
			// 레코드 1줄 -> BoardDTO 1개
			BoardDTO dto = new BoardDTO();
			
			dto.setSeq(rs.getString("seq"));
			// dto.setId(rs.getString("id"));
			dto.setName(rs.getString("name"));
			dto.setSubject(rs.getString("subject"));
			dto.setReadcount(rs.getString("readcount"));
			dto.setRegdate(rs.getString("regdate"));
			dto.setIsnew(rs.getString("isnew")); // 글쓰고 난뒤 며칠이 지났는지 시간
			dto.setCcnt(rs.getString("ccnt")); // 현재 글에 달린 댓글 갯수
			
			list.add(dto);
			
		}
		
		return list;
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return null;
}

 

[ Servlet 작업 - 댓글 작성하기 ]

1) com.test.myapp.board > AddComment.java

- view.jsp에서 form method="POST"으로 넘겨 받으므로, doPost

- 데이터 가져오기 ( content, pseq )

- DB작업 

- 돌아가기 > view.do?seq=번호

@WebServlet("/board/addcomment.do")
public class AddComment extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 1. 데이터 가져오기(content, pseq)
		String pseq = req.getParameter("pseq"); // 보고있던 글번호(= 작성중인 댓글의 부모 글번호)
		String content = req.getParameter("content");
		
		// 2. DB 작업 > DAO 위임 > insert
		BoardDAO dao = new BoardDAO();
		CommentDTO dto = new CommentDTO();
		
		HttpSession session = req.getSession();
		
		dto.setId(session.getAttribute("id").toString()); // 댓글 작성자 아이디(= 로그인한 사람 세션)
		dto.setPseq(pseq);
		dto.setContent(content);
		
		int result = dao.addComment(dto); // 1, 0		
		
		// 3. 돌아가기 > view.do?seq=10
		if (result == 1) {
			resp.sendRedirect("/myapp/board/view.do?seq=" + pseq); //보고 있던 글번호를 가지고 돌아가기
		} else {
			
			resp.setCharacterEncoding("UTF-8");
			
			PrintWriter writer = resp.getWriter();			
			
			writer.print("<html>");
			writer.print("<body>");
			writer.print("<script>");
			writer.print("alert('댓글 쓰기 실패');");
			writer.print("history.back();");
			writer.print("</script>");
			writer.print("</body>");
			writer.print("</html>");
			
			writer.close();
		}
	}
}

 

[ JSP 작업 - 게시판 리스트 페이지에서 댓글수 출력하기 ] 

1) WEB-INF > views > board > list.jsp

- 미리 DB 작업(BoardDAO.java) 할때 만들어두었던 ccnt 호출

- 게시판 리스트의 제목(content) 옆에 부트스트랩을 이용해서 댓글수 나타내기

- 게시판 글 내용에 댓글이 없다면 나타내지 않는다.

*어제 작성했던 파일 그대로 사용했으며, 어제 구현했던 코드는 일부 제거했습니다.

<h1>Board <small>List</small></h1>

<c:if test="${map.isSearch == 'y'}">
	<div class="searchBar">
		'${ map.search }'으로 검색한 결과 ${ list.size() }개의 게시물이 있습니다.
	</div>
</c:if>

<table class="table table-bordered">
	<tr>
		<th>번호</th>
		<th>제목</th>
		<th>이름</th>
		<th>날짜</th>
		<th>조회수</th>
	</tr>
	<c:forEach items="${ list }" var="dto">
	<tr>
		<td>${ dto.seq }</td>
		<td>
			<a href="/myapp/board/view.do?seq=${ dto.seq }&column=${ map.column }&search=${ map.search }">${ dto.subject }</a>
			<c:if test="${ dto.ccnt > 0 }">
			<span class="badge">${ dto.ccnt }</span>
			</c:if>
			
			<c:if test="${ dto.isnew < (2 / 24)}">
			<span class="label label-danger">new</span>
			</c:if>
		</td>
		<td>${ dto.name }</td>
		<td>${ dto.regdate }</td>
		<td>${ dto.readcount }</td>
	</tr>
	</c:forEach>
</table>

 

- 게시판 상세 페이지 (댓글 작성) - ( http://localhost:8090/myapp/board/view.do?seq=45 )

   --> 주의사항: 로그인을 해야 session에 기록되므로 로그인을 꼭 할 것 (안하면 500 ERROR)

 

- 게시판 리스트 페이지 (댓글 수) - ( http://localhost:8090/myapp/board/list.do?column=&search= )

 

3. 댓글 삭제하기

[ 구현 목표 ]

- 게시판 글에 작성한 댓글을 삭제할 수 있다.

- 게시판 글을 삭제하면 해당 글의 댓글은 자동적으로 전부 삭제된다.

 

[ DB 작업 ]

1) com.test.myapp.board > BoardDAO.java

- 글 내용 상세 페이지(View)에서 댓글 삭제를 위한 메소드

public int delComment(String seq) {
	
	try {
		
		String sql = "delete from tblComment where seq = ?";
		
		pstat = conn.prepareStatement(sql);
		
		pstat.setString(1, seq);
		
		return pstat.executeUpdate(); // 성공시 1 실패시 0
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return 0;
}

 

- 해당 게시물 삭제시(DelOk.java) 기존의 모든 댓글 삭제 처리하기 메소드

- 게시물글을 부모seq로 댓글 테이블이 전달 받았으므로, 게시물 삭제를 위해서는 자식seq인 댓글을 삭제해야한다.

public void delAllComment(String seq) {
	
	try {
		
		String sql = "delete from tblComment where pseq = ?";
		
		pstat = conn.prepareStatement(sql);
		pstat.setString(1, seq);	
		pstat.executeUpdate(); // 성공시 1 실패시 0
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
}

 

[ Servlet 작업 - 댓글 삭제하기 ]

1) com.test.myapp.board > DelComment.java

- 데이터 가져오기 (seq, pseq)

- DB 작업

- 돌아가기 > view.do?seq=부모번호

@WebServlet("/board/delcomment.do")
public class DelComment extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 1. 데이터 가져오기 (seq, pseq)
		String pseq = req.getParameter("pseq"); // 보고있던 글번호(= 작성중인 댓글의 부모 글번호)
		String seq = req.getParameter("seq"); // 삭제할 글번호
		
		// 2. DB 작업 > DAO 위임 > delete
		BoardDAO dao = new BoardDAO();
		
		int result = dao.delComment(seq); // 1, 0		
		
		// 3. 결과 후 처리
		if (result == 1) {
			resp.sendRedirect("/myapp/board/view.do?seq=" + pseq); //보고 있던 글번호를 가지고 돌아가기
		} else {
			
			resp.setCharacterEncoding("UTF-8");
			
			PrintWriter writer = resp.getWriter();			
			
			writer.print("<html>");
			writer.print("<body>");
			writer.print("<script>");
			writer.print("alert('댓글 삭제 실패');");
			writer.print("history.back();");
			writer.print("</script>");
			writer.print("</body>");
			writer.print("</html>");
			
			writer.close();
		}

	}
}

 

2) com.test.myapp.board > DelOk.java

- 게시글 삭제 시 댓글 내용을 자식seq으로 받았으므로 게시글 삭제 전, 댓글 먼저 삭제해야한다.

@WebServlet("/board/delok.do")
public class DelOk extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 1.
		String seq = req.getParameter("seq");
		
		// 2.
		BoardDAO dao = new BoardDAO();
		
		// 2.5 현재 글에 달린 댓글부터 삭제하기(***)
		dao.delAllComment(seq); // 부모글번호
		
		int result = dao.del(seq);
		// 3.
		if ( result == 1 ) {
			resp.sendRedirect("/myapp/board/list.do");
		} else {
			resp.sendRedirect("/myapp/board/del.do?seq=" + seq);
		}
	}

}

 

- 게시판 상세 페이지 (삭제 전) - ( http://localhost:8090/myapp/board/view.do?seq=45 )

 

- 게시판 상세 페이지 (삭제 후) - ( http://localhost:8090/myapp/board/view.do?seq=45 )