부모글과 차수 정보로 답글의 정렬과 그룹핑 문제를 해결할 수 있다는 게 재밌었음ㅎㅎ 페이징도 그렇고 뭔가 새로운 기능을 추가하려면 과정이 길고 복잡한 거 같은데 문제를 해결하는 키 아이디어는 단순함.. 과정도 이 정도는 별 거 아니지~! 할 수 있을 정도가 되려면 이건 또 몇 번을 더 만들어봐야 할까 푸핫
새 글을 기준으로 한 게시글 그룹
답글이 작성된 원본글 번호
null
이어야 하고, 없는 글 번호를 부모글로 가질 수 없음같은 테이블
의 컬럼을 참조함 → 자기참조 외래키(재귀)들여쓰기 횟수 (트리구조에서의 level or depth)
-- 테이블에 계층형 게시판 항목 추가
alter table board add board_group number;
alter table board add board_parent references board(board_no);
alter table board add board_depth number;
update board set board_group = board_no;
update board set board_depth = 0;
commit;
-- 이제 null이 없으니까 not null 조건 추가 가능
alter table board modify board_group not null;
alter table board modify board_depth not null;
private int boardGroup, boardParent, boardDepth;
추가
//코드 추가
.boardGroup(rs.getInt("board_group"))
.boardParent(rs.getInt("board_parent"))
.boardDepth(rs.getInt("board_depth"))
board_parent == null && board_depth == 0
select * from board \[검색 조건]
connect by prior A=B (A가 상위 컬럼)
: 번호와 상위글 번호가 같은 글 출력(글 번호가 상위 컬럼)
start with board_parent is null
: board_parent가 null인 글이 시작점
order siblings by \[정렬 조건]
: 연관된 항목들 꺼내기, 여러 개면 조건 순 정렬
DaoImpl에서 검색 결과/목록 조회 메소드의 order by
절을 변경
connect by prior board_no = board_parent
start with board_parent is null
order siblings by board_group desc, board_no asc
차수만큼 제목이 들여쓰기 되도록 view 수정
<!-- list.jsp -->
<c:forEach var="i" begin="1" end="${boardDto.boardDepth}" step="1">
</c:forEach>
+) 답글이면 parent != 0, depth > 0
(새)글쓰기와 답글쓰기 모두 글쓰기 매핑 주소를 사용하지만 구분이 되어야 함. boardParent를 주소에 파라미터로 추가
boardParent가 주소 파라미터에 있으면 답글, 없으면 새글
<%-- detail.jsp 회원만 글쓰기/답글쓰기 --%>
<c:if test="${loginId != null}">
<h2><a href="write">글쓰기</a></h2>
<h2><a href="write?boardParent=${boardDto.boardNo}">답글쓰기</a></h2>
</c:if>
boardParent가 주소 파라미터에 있으면 답글
<form action="write" method="post">
<%-- 답글이라면 부모글번호를 추가로 전송하도록 처리 --%>
<c:if test="${isReply}">
<input type="hidden" name="boardParent" value="${param.boardParent}">
</c:if>
답글일 때 파라미터를 추가했지만, modelAttribute에 자동으로 추가되도록하기 위해서 boardDto 필드와 이름을 맞췄으므로 추가 수정 불필요
<c:set var="isReply" value="${param.boardParent != null}"></c:set>
<c:choose>
<c:when test="${isReply}">
<h1>답글쓰기</h1>
</c:when>
<c:otherwise>
<h1>글쓰기</h1>
</c:otherwise>
</c:choose>
새글/답글 구분해서 글번호 넣어주도록 수정 필요
답글일 때 부모글의 그룹번호, 차수 등을 추가로 더 조회해야 함
[문제점] 등록 메소드 하나에 기능이 너무 많아짐
DAO에는 통상적으로 딱 하나의 기능을 할 수 있는 메소드들만 구현함(나중에 부르기 쉬우니까)
→ 컨트롤러에서 DB 접속하도록 우선 구현한 다음에 해당 내용을 나중에 서비스로 이관할 예정
[문제점] 그룹번호에 시퀀스 번호 넣어야 하는데 그걸 insert2에서 가져오니까 문제가 됨
→ 등록 메소드에서 시퀀스 부여 기능 분리
@Override
public int sequence() {
String sql = "select board_seq.nextval from dual";
int boardNo = jdbcTemplate.queryForObject(sql, int.class);
return boardNo;
}
@Override
public void insert2(BoardDto boardDto) {
String sql = "insert into board("
+ "board_no, board_head, board_title, board_content, "
+ "board_writer, board_group, board_parent, board_depth) "
+ "values(?, ?, ?, ?, ?, ?, ?, ?)";
Object[] param = {
boardDto.getBoardNo(),
boardDto.getBoardHead(),
boardDto.getBoardTitle(),
boardDto.getBoardContent(),
boardDto.getBoardWriter(),
boardDto.getBoardGroup(),
boardDto.getBoardParent(),
boardDto.getBoardDepth()
};
jdbcTemplate.update(sql, param);
}
/write에서 등록 메소드 실행 전에 번호를 미리 생성하고 새글/답글 구분하도록 처리
//번호 미리 생성
int boardNo = boardDao.sequence();
boardDto.setBoardNo(boardNo);
//등록 전에 새글/답글 구분해서 그에 맞는 계산 수행
if(boardDto.getBoardParent()==0) {//새글(int로 선언해서 null아니고 0)
boardDto.setBoardGroup(boardNo);
boardDto.setBoardParent(0); //기본값 어차피 0
boardDto.setBoardDepth(0); //기본값 어차피 0
}else {//답글
BoardDto parentDto = boardDao.selectOne(boardDto.getBoardParent());
boardDto.setBoardGroup(parentDto.getBoardGroup());
boardDto.setBoardDepth(parentDto.getBoardGroup()+1);
}
위 내용대로 수정하고 등록되는지 확인해보면 에러 발생함
원인: DB에 들어갈 때는 새글의 parent가 0이 아니라 null로 들어가야함
해결책: parent가 0이면 null로 바꿔서 들어가도록 수정
//DB에 insert할 때 0대신 null이 등록되도록 값을 변환해서 반환
public Object getBoardParentInteger() {
if(boardParent == 0) {
return null;
}else {
return boardParent;
}
}