JSP - 계층형 게시판 로직
25 Feb 2021 | JSPJSP - 계층형 게시판 로직
답글을 달 수 있는 계층형 게시판을 구현해보자.
답글은 댓글과는 다르게 남이 올린 글에 답변으로 새 글을 쓰는 것이다.
우선 DB 테이블을 만드는데 pk인 num은 1씩 증가하는 속성을 갖는다.
oracle의 sequence로 표현하자면 다음과 같다.
CREATE SEQUENCE board_seq --시퀀스명
START WITH 1 -- 시작값 1
INCREMENT BY 1 -- 증가값 1
NOMAXVALUE -- 최대값 무한대
NOCACHE
NOCYCLE;
또 중요한 필드는 ref, step, depth 세 가지이다.
이 변수들은 계층형 게시판 로직의 핵심이다.
ref는 그룹이고 step은 같은 그룹 내의 순서, depth는 들여쓰기를 뜻한다.
변수를 두 개만 쓰는 방식은 게시글을 하나만 써도 전체 목록이 업데이트가 되기 때문에 DB에 부하가 걸려서 Q&A와 같이 글 수 자체가 적은 곳들 빼고는 선호되지 않는다.
게시판은 새 글을 쓰는 경우와 답글을 쓰는 경우 두 가지로 나뉜다.
먼저, 새 글을 쓰는 경우의 순서도는 다음과 같다.
- ref = num : 이 방식은 수정, 삭제등이 일어나면 잃어버리는 번호가 많아 기술적으로 선호되지 않는다. max(ref) + 1 : 이전 글들의 ref 중 최대값을 찾아 1을 증가시키는 방법이 선호된다. 초기값은 null
- step = 0, depth = 0 : 새 글은 그룹을 제외하고는 무조건 첫번째이므로 순서,들여쓰기의 초기값은 0이다.
다음은 답글을 다는 경우의 순서도이다.
- 원글의 ref, step, depth를 복사 : 답글을 달 원글의 ref, step, depth를 복사한다.
- 같은 그룹(ref)내에서 자신보다 큰 step의 값을 1 증가시킴 : 원글에 답글을 달고, 또 거기에 답글을 달고, 다시 원글에 답글을 다는 경우의 순서를 정리하기 위해 자신보다 큰 step에 1을 더해야한다.
- 자신의 step + 1, depth + 1 : 자신도 답글이므로 순서와 들여쓰기를 증가시킨다.
이제 코드로 이를 작성하는데 위의 로직은 DAO에서 DB에 insert 할 때 쓰인다.
먼저, 글을 작성하는 writeForm.jsp 부분이다.(자잘한 부분 생략)
<!-- writeForm.jsp -->
<%
int num=0, ref=1, step=0, depth=0;
try {
if(request.getParameter("num") != null) {
num = Integer.parseInt(request.getParameter("num"));
ref = Integer.parseInt(request.getParameter("ref"));
step = Integer.parseInt(request.getParameter("step"));
depth = Integer.parseInt(request.getParameter("depth"));
}
%>
이 writeForm은 새 글 쓰기, 답글 쓰기 두 가지 방식에서 모두 쓰이므로 새 글, 답글을 구분할 수 있어야한다. 만약 답글을 쓰기 위해 다른 곳에서 날린 HTTP request에 num 값이 있으면 원글의 num, ref, step, depth를 저장하고 아니면 ref=1을 제외한 다른 변수들은 0으로 초기화한다. 이 num값은 DAO에서 새 글인지 답글 쓰기인지 판별하는데 쓰인다. writeForm에서는 form과 input태그로 사용자가 작성한 게시글의 정보를 writeProc.jsp에 submit을 하게 된다.
<!-- writeProc.jsp -->
<jsp:useBean id="article" scope="page" class="boardone.BoardVO">
<jsp:setProperty name="article" property="*" />
</jsp:useBean>
<%
BoardDAO dao = BoardDAO.getInstance();
dao.insertArticle(article);
response.sendRedirect("list.jsp");
%>
writeProc에서는 writeForm에서 날린 게시글 관련 데이터를 VO에 담고 이를 통해 DAO의 insert 메소드를 호출해 DB에 게시글을 저장하는 기능을 한다. 작업을 마친 후 게시글 목록이 있는 list.jsp로 redirect 시킨다.
// BoardDAO.java
public void insertArticle(BoardVO article) {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
// 답글 1번 부분 로직
int num = article.getNum();
int ref = article.getRef();
int step = article.getStep();
int depth = article.getDepth();
int number = 0; //
String sql = "";
try {
conn = ConnUtil.getConnection();
// 새 글 1번 부분 로직
pstm = conn.prepareStatement("select max(ref) from board");
rs = pstm.executeQuery();
if(rs.next()) {
number = rs.getInt(1) + 1;
} else {
number = 1;
}
// 답글일 경우
if(num != 0) {
// 답글 2번 부분 로직
sql = "update board set step=step+1 where ref=? and step > ?";
pstm = conn.prepareStatement(sql);
pstm.setInt(1,ref);
pstm.setInt(2,step);
pstm.executeUpdate();
// 답글 3번 부분 로직
step+=1;
depth+=1;
} else { // 새 글일 경우
// 새 글 2번 부분 로직
ref = number;
step = 0;
depth = 0;
System.out.println("새글입니다.");
}
sql = "insert into board(num,subject,content,ref,step,depth) values(board_seq.nextval,?,?,?,?,?)";
pstm = conn.prepareStatement(sql);
pstm.setString(1, article.getSubject());
pstm.setString(2, article.getContent());
pstm.setInt(3, ref);
pstm.setInt(4, step);
pstm.setInt(5, depth);
pstm.executeQuery();
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try {rs.close();} catch(SQLException e) {}
if(pstm != null) try {pstm.close();} catch(SQLException e) {}
if(conn != null) try {conn.close();} catch(SQLException e) {}
}
}
앞서 설명한 계층형 게시판의 로직이 들어가는 DAO의 insert메소드이다.
writeProc에서 넘긴 VO의 게시글 데이터를 받아 num, ref, step, depth를 저장한다.(답글 1번 부분 로직)
DB에서 max(ref)를 조회하지만 최초 데이터는 없으므로 null이 반환되고 그 때는 다른 변수 number를 1로 초기화한다. 값이 있는 경우엔 제일 큰 ref에서 1을 증가시킨 값을 number에 저장한다. (새 글 1번 부분 로직)
num = 0은 새 글을 쓰는 경우이며 ref에 number 값을 대입해 그룹 번호 순서를 맞춘다. 최초의 새 글 ref = 1이 된다. 새 글이므로 모든 경우에서 step, depth는 0이 된다. (새 글 2번 부분 로직)
num != 0이면 답글을 다는 경우이며 원글의 ref를 찾아 해당 row에서 원글의 step보다 큰 step의 값을 1씩 증가시킨다. (답글 2번 부분 로직)
step과 depth를 1씩 증가시킨다. (답글 3번 부분 로직)
최종적으로 DB에 insert를 하고 자원을 반납한다.
list.jsp에서는 DB에서 게시글을 받아 렌더링을 해주면 되고 게시글을 선택하여 상세 내용을 보는 content.jsp 페이지를 만들고 그 곳에서 답글을 다는 버튼을 누르면 writeForm.jsp에 해당 원글의 num, ref, step, depth를 넘겨주게 된다.
참고 자료
KG 아이티뱅크 강의 자료
처음해보는 JSP&Servlet 웹 프로그래밍