일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 게시판댓글수
- 스프링
- SCOPE
- 게시판프로젝트
- request영역
- 회원정보
- session영역
- 시큐리티
- 내장객체
- 게시판댓글
- 댓글수처리
- Security
- Spring
- RPTLANFTN
- 스프링회원정보수정
- page영역
- 스프링시큐리티
- jsp
- ResponseEntity
- application영역
- 회원정보수정
- Today
- Total
코코무의 코딩캔버스
[Spring] 댓글과 댓글 수에 대한 처리 본문
※ 본 글은 교재 [코드로 배우는 스프링 웹 프로젝트 - 구멍가게 코딩단]을 바탕으로 작성되었습니다.
🧙♂️ 안녕하세요 코딩법사입니다.
이어서 게시판 프로젝트의 댓글 처리입니다.
게시판을 사용할 때 보면, 제목 옆에 댓글 수가 뜨는 것을 심심치 않게 볼 수 있습니다.
이번 포스팅에서는 그 부분을 만져줄 것입니다.
그렇다면 먼저 댓글 수를 의미하는 칼럼을 추가해야 합니다.
alter table tbl_board add (replyCnt number default 0);
그리고 기존에 댓글이 존재했다면 replyCnt에 반영해야 하기 때문에 update를 사용한 쿼리를 실행합니다.
update tbl_board set replyCnt = (select count(rno) from tbl_reply
where tbl_reply.bno = tbl_board.bno);
프로젝트 수정
데이터베이스가 수정되었으므로 BoardVO 클래스와 MyBatis의 SQL, BoardService 등을 수정합니다.
1. BoardVO, BoardMapper 수정
//BoardVO
private int replyCnt;
//BoardMapper 인터페이스
public void updateReplyCnt(@Param("bno") Long bno, @Param("amount") int mount);
updateReplyCnt( )는 해당 게시물의 번호인 bno와 증가나 감소를 의미하는 amount 변수에 파라미터를 받을 수 있게 처리합니다.
댓글이 등록되면 1이 증가하고, 댓글이 삭제되면 1이 감소합니다.
MyBatis의 SQL을 처리하기 위해서는 원래는 기본적으로 하나의 파라미터 타입을 사용하기 때문에
위와 같이 2개 이상의 데이터를 전달하려면 @Param 어노테이션을 이용해서 처리합니다.
<!-- BoardMapper.xml -->
<update id="updateReplyCnt">
update tl_board set replycnt = replycnt + #{amount} where bno = #{bno}
</update>
댓글이 추가되면 반정규화된 tbl_board 테이블에 replycnt 칼럼이 업데이트되어야 하므로
Mapper.xml에 updateReplyCnt 구문이 추가되어야 합니다.
게시물의 목록을 처리하는 부분에서는 새롭게 추가된 replycnt 칼럼을 가져오도록 인라인뷰 내에 추가하고
바깥쪽 select에도 추가합니다.
2. ReplyServiceImpl의 트랜잭션 처리
ReplyServiceImpl 클래스는 기존에는 ReplyMapper만 이용했지만,
반정규화 처리가 되면서 BoardMapper를 같이 이용해야 하는 상황이 되었습니다.
ReplyServiceImpl에서 새로운 댓글이 추가되거나 삭제되는 상황이되면
BoardMapper와 ReplyMapper를 같이 이용해 처리하며 이 작업은 트랜잭션으로 처리되어야 합니다.
예를 들어 Reply 데이터에서는 댓글이 삭제되었는데 Board 데이터에서는 삭제되지 않으면 안되겠죠.
//ReplyServiceImpl 클래스에 추가
@Setter(onMethod_ = @Autowired)
private BoardMapper mapper;
@Transactional
@Override
public int register(ReplyVO vo) {
log.info("register...." + vo);
boardMapper.updateReplyCnt(vo.getBno(), 1);
return mapper.insert(vo);
}
..생략..
@Transactional
@Override
public int remove(Long rno) {
log.info("remove...." + vo);
ReplyVO vo = mapper.read(rno);
boardMapper.updateReplyCnt(vo.getBno(), -1);
return mapper.delete(rno);
}
댓글 등록은 파라미터로 전달받은 ReplyVO 내에 게시물의 번호가 존재하므로 이것을 이용해 댓글을 추가합니다.
댓글 삭제는 전달되는 파라미터가 댓글의 번호인 rno만을 받기 때문에(bno는 파라미터로 안 받으니 알 턱이 없네요)
해당 댓글의 게시물(bno)을 알아내야 합니다.
때문에
'ReplyVO vo = mapper.read(rno);를 사용하여
ReplyMapper에 있는, 댓글 번호를 알고 있는 read 메서드(ReplyVO 타입이기 때문에 알고있음)를 호출해
여기서 의문이 듭니다.
애초에 Long rno와 Long bno까지 모두 가진 ReplyVO 객체를 파라미터로 받지 않는 이유는 무엇일까?
ReplyVO 객체로 한 번에 해결할 수 있지 않을까?
그래서 실제로 ReplyVO 객체만을 파라미터로 받는 'register( ) '와 'modify( )'는 뭐가 다른지 살펴보았습니다.
영문을 알기 위해 영속 계층까지 가보았습니다.
해당 메서드들은 Mapper 인터페이스에서 각각 'insert( )'와 'update( )'로 명시되어 있습니다.
그리고 XML에 가보면,
쿼리문에 ReplyVO의 여러 필드값들이 사용되고 있는 것을 볼 수 있었습니다.
반면 Long rno를 파라미터로 받는 'get( )'과 'remove( )'는
(각각 인터페이스에서 'read( )'와 'delete( )'로 명시되어 있습니다)
XML의 쿼리문에서 간단하게 rno만이 사용되고 있는 것을 확인했습니다.
검증되지 않은 사견이지만
ReplyVO 객체를 파라미터로 사용해도 안 될 것은 없어보이나,
불필요한 것으로 보여집니다.
------------------------------------
참고로 'read( )'('get( )')만이 CRUD 중에서 int 타입이 아니라 ReplyVO로 반환되는 이유는
다른 동작들은 간단하게 int만으로도 해결되지만
해당 메서드는 ReplyVO 객체의 값들을 모두 읽어와야 하기 때문입니다.
(선택된 rno 값 하나만으로 모든 것을 읽어올 수 있을 줄 알았으나 저의 오산이었습니다)
파라미터로 게시물의 번호(bno)를 받을 수 있으면 좋겠지만
그렇다면 ReplyController까지 같이 수정(파라미터에 추가)해야 합니다.
3. 화면 수정
백 쪽에서 댓글 수가 출력될 수 있도록 수정했으니
프론트에서도 수정을 해줘야 합니다.
list.jsp에서 출력되게 할 것이므로
<c:forEach items="${list}" var="board"> <!-- list의 값들을 반복 출력하는데 그 하나 하나의 이름이 board -->
<tr>
<td><c:out value="${board.bno}" /></td> <!-- 게시물 번호 -->
<td>
<a class='move' href='<c:out value="${board.bno}"/>'> <!-- 게시물 제목 클릭 시 게시물 번호 좌측 하단 경로에 띄우기 -->
<c:out value="${board.title}" /> <!-- 게시물 제목 -->
<b>[ c:out value="${board.replyCnt}" /> ]</b> <!-- 진하게/[댓글 수] -->
</a>
</td>
<td><c:out value="${board.writer}" /></td> <!-- 작성자 -->
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${board.updateDate}" /></td> <!-- 최종 수정일 -->
</tr>
</c:forEach>
다음과 같이 수정합니다.
EL 내에 있는 list는
BoardController에서 service.getList( )를 담은 값입니다.
service.getList( )는 BoardMapper 인터페이스의 getListWithPaging( )를 호출하여
BoardVO 타입의 객체로 List 배열에 담아 반환합니다.
getListWithPaging( )는 BoardMapper.xml에서 쿼리문을 사용해 페이징 처리가 된 목록을 보여주는 메서드로
페이징 처리를 하기 위해 Criteria 타입 객체를 파라미터로 전달합니다.
정리하면,
list는 List 배열에 담긴 페이징 처리가 된 목록들의 인덱스 반환값입니다.
수정하고나서 웹 브라우저를 보면
와 개쩐다!
좀 더 그럴 듯한 게시판의 모습으로 변모하게 됩니다.
이번 포스팅에서는 댓글 수 처리에 대해 다뤄보았습니다.
총총🐰
'Spring' 카테고리의 다른 글
[Spring] @ResponseBody의 개념과 용도(feat. PrintWriter) (0) | 2024.07.23 |
---|---|
[Spring] ResponseEntity의 개념 및 사용법 (0) | 2024.03.15 |
[Spring] AOP와 트랜잭션(@Transactional) (0) | 2024.03.08 |
[Spring] AOP에 대하여 (0) | 2024.03.07 |
[Spring] 댓글 처리(REST와 Ajax...스압주의) (0) | 2024.03.07 |