1. 쿼리 작성
더미데이터 추가
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글1', 1, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글2', 4, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글3', 4, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글4', 4, 2, now());
select rt.id, rt.user_id, rt.comment, ut.username from reply_tb rt
inner join user_tb ut on rt.user_id = ut.id where rt.board_id = 4 ;

게시글에 작성된 댓글을 표시한다. 화면에는 username 과 comment 만 출력하지만 댓글의 작성자 여부를 확인하기 위해 id 와 userId 도 함께 받아온다.
2. DTO 만들기
댓글 테이블에서 받은 데이터를 boardResponse 에 DTO로 받는다. 댓글을 게시글에 출력해야 하기 때문이다.
package shop.mtcoding.blog.board;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.Data;
import shop.mtcoding.blog.user.User;
import java.util.List;
public class BoardResponse {
@Data
public static class DetailDTO {
private Integer id;
private String title;
private String content;
private Integer userId;
private String username;
@Data
public static class ReplyDTO {
private Integer id;
private Integer userId;
private String username;
private String comment;
public ReplyDTO(Object[] ob,User sessionUser) {
this.id = (Integer) ob[0];
this.userId = (Integer) ob[1];
this.comment = (String) ob[2];
this.username = (String) ob[3];
}
}
}

기존 BoardResponse 는 DB에서 조회된 게시글 테이블을 받는 DTO였다. 여기에 댓글 테이블을 받는 DTO를 합친다.
ReplyDTO를 컬렉션 형태로 받는 이유는 하나의 게시글에 여러 개의 댓글이 표현되어야 하기 때문이다. 컬렉션 형태로 mustache 에 전달하면 반복문의 형태가 된다.

3. 컨트롤러
@GetMapping("/board/{id}")
public String detail(@PathVariable int id,HttpServletRequest request) {
User sessionUser = (User) session.getAttribute("sessionUser"); // 세션의 id
if(sessionUser!=null){ // 세션의 값이 null 이 아니어야 로그인 상태
if(boardUserId==sessionUser.getId()){ 세션 id = 게시글 작성 id 비교
owner = true; // 일치하면 권한 활성
}
request.setAttribute("owner",owner); // View 에 전달
}
//DB데이터를 DetailDTO에 받음
BoardResponse.DetailDTO boardDTO = boardRepository.findByIdWithUser(id);
//DB데이터를 ReplyDTO에 받음
List<BoardResponse.ReplyDTO> replyDTOList = replyRepository.findByBoardId(id,sessionUser);
//게시글 데이터를 view 로 가져감
request.setAttribute("board", boardDTO);
//댓글 데이터를 view 로 가져감
request.setAttribute("replyList",replyDTOList);
return "board/detail";
}
댓글은 게시글에 출력되기 때문에 boardController 의 상세보기 메서드에 작성한다.
레파지토리에 게시판 번호와 세션의 회원ID를 가져간다 세션 회원 ID는 추후에 댓글의 작성자 여부를 확인할 때 사용한다.
4. 레파지토리
public List<BoardResponse.ReplyDTO> findByBoardId(int boardId, User sessionUser) {
Query query = em.createNativeQuery("select rt.id, rt.user_id, rt.comment, ut.username from reply_tb rt \n" +
"inner join user_tb ut on rt.user_id = ut.id where rt.board_id = ?");
query.setParameter(1,boardId);
List<Object[]> obs = query.getResultList();
//DB에서 받은 정보를 ReplyDTO에 로그인한 User 정보와 함께 받는다.
return obs.stream().map(ob -> new BoardResponse.ReplyDTO(ob,sessionUser)).toList();
}
게시글 번호로 테이블을 조회한다.
Stream API 를 통해 ReplyDTO 로 받은 테이블 데이터를 오브젝트 배열 형태로 담는다.
5. View
<!-- 댓글아이템 -->
{{#replyList}}
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">{{username}}</div>
<div>{{comment}}</div>
</div>
<form action="/reply/1/delete" method="post">
<button class="btn">🗑</button>
</form>
</div>
{{/replyList}}
replyList 는 컬렉션 형태기 때문에 {{#replyList}} {{/replyList}} 는 mustache 에서 반복문 형태가 된다. 따라서 댓글 테이블이 여러개라면 반복문을 돌면서 출력한다.

4번 게시글에 댓글이 정상적으로 출력된다.

게시글이 없는 댓글은 출력되지 않는다.

댓글을 작성하면 리스트에 출력이 된다.
Share article