현재 문의사항 게시판은 기본적인 CRUD + 게시물 상세화면에서 정보 가져와 답글 등록 + 답글 등록/삭제 시 기존 게시물 상태변경까지 가능한 상태였다. 답글을 만드는건 좋은데, 목록 조회에서 기존게시물 사이사이에 답글이 달리게 하려면 현 테이블 구조로는 어렵다는 것을 깨닫고 방법을 검색해보았다.
내가 참고한 방법은 oracle의 계층 구조 쿼리를 사용하는 방법이다. 오라클의 START WITH
, CONNECT BY
, ORDER SIBILINGS BY
를 사용했다.
예시 블로그에선 기준이 되는 게시물id, 부모 id 등이 전부 정수로 되어있었는데, 내 프로젝트는 id값이 전부 문자열이기도 하고 조회 쿼리도 복잡해서 먼저 정수id를 가진 테스트 테이블을 만들어서 연습해보았다.
ex)
3
----6
2
----5
1
----4
BOARD_ID
, TITLE
, PARENT_ID
, GROUP_ID
, LV
컬럼을 가진 테이블을 생성했다.BOARD_ID
: 게시물 ID, 게시물 고유 번호TITLE
: 게시물 제목. LV
컬럼 값에 따라 들여쓰기 기능을 구현하기 위해 추가PARENT_ID
: 부모ID, 일반 게시물일 경우 0
, 답글 게시물일 경우 부모의 BOARD_ID
저장GROUP_ID
: 그룹ID, 게시물 ORDER 기준이 됨. 일반 게시물일 경우 BOARD_ID
, 답글 게시물일 경우 PARENT_ID
저장LV
: 게시물의 깊이 (level, depth) 저장. 깊이만큼 제목 앞에 들여쓰기하기 위해 추가/* ID = NUMBER */
SELECT board_id, LPAD(' ', 4*(lv-1)) || title title, parent_id, lv, group_id FROM TEST
START WITH parent_id=0
CONNECT BY PRIOR board_id=parent_id
ORDER SIBLINGS BY group_id desc;
egov 프로젝트를 한다면 전자정부에서 제공하는 idgen
을 사용하게 되는데, 문자열과 숫자 조합을 많이 사용한다. 그래서 id가 문자열이어도 정렬이 잘 될까 걱정이었는데, 문자열을 별도로 잘라서 숫자처리하지 않아도 정렬이 잘 되는 것을 확인했다.
/* ID = VARCHAR */
SELECT board_id, LPAD(' ', 4*(lv-1)) || title title, parent_id, lv, group_id FROM TEST2
START WITH parent_id='TEST-000'
CONNECT BY PRIOR board_id=parent_id
ORDER SIBLINGS BY group_id desc;
연습용 테이블에 비해 실제 프로젝트의 조회 쿼리는 굉장히 복잡하지만, 결국 필요한 컬럼과 코드는 동일해서 작성하기 어렵지 않았다.
mapper.xml
의 sql 쿼리 변경L
이 자꾸 소문자가 아닌 대문자로 들어가는 문제가 있어 나중에 jsp의 컬럼명과 맞지 않는 등의 문제가 있었다. 어쩔 수 없이 DB의 컬럼명은 LV
로 하고 mapper에서 받을 때는 depth
라는 이름을 쓰기로 했다.WHERE
절 뒤에 START WITH~
절을 넣어주었다.// 새로운 답글 게시물 생성해서 대상ID, 답글여부, 제목, 내용 미리 설정
QnAVO reply = new QnAVO(); // 답글 게시물 생성
reply.setQtId(prevVO.getQnaId()); // 기존게시물의 id 저장
reply.setIsAnswer(1); // 답글여부 0/1
reply.setQnaSj("[RE]:" + prevVO.getQnaSj()); // 기존 게시물의 제목에 [re] 추가
String replyCn = getHtmlStrCnvr(prevVO.getQnaCn()) + "<br/><br/>------------------------------------------------------<br/><br/>"; // 기존 게시물 내용에 점선 및 줄바꿈 삽입
reply.setQnaCn(replyCn);
/* 답글 정렬용 데이터 삽입 */
reply.setParentId(prevVO.getQnaId());
reply.setGroupId(prevVO.getQnaId());
reply.setDepth(prevVO.getDepth()+1); // 기존 게시물 레벨+1
model.addAttribute("qnaVO", reply);
<input name="parentId" type="hidden" value="<c:out value='${result.parentId}'/>"/>
<input name="groupId" type="hidden" value="<c:out value='${result.groupId}'/>"/>
<input name="depth" type="hidden" value="<c:out value='${result.depth}'/>"/>
사실 sql 쿼리는 쉽게 작성했는데, 작성한 xml mapper 파일이 프로젝트에 적용되지 않아서 오후 내내 머리를 싸맸다. 분명 파일을 잘 수정해뒀는데 sql 쿼리처리 로그를 보면 수정 전 코드가 돌아가고 있었다.
수많은 블로그를 돌아다니며 여러 방법을 시도해봤지만, 알고보니 문제는 아주 쉬운 것이었다. 바로 eclipse-project-Build Automatically
가 선택되어 있지 않았던 것...!
egov-mapper:소스 변경 시 적용이 잘 되지 않습니다.
도대체 이거때문에 몇 번을 clean, build하고 껐다 켰는지... 그래도 오늘 안에 알아내서 정말 다행이다.