게시판에 댓글을 구현해 볼 것이다.
detail.mustache를 수정하자
{{>layout/header}}
<div class="container p-5">
<!-- 수정삭제버튼 -->
{{#model.isOwner}}
<div class="d-flex justify-content-end">
<a href="/api/board/{{model.id}}/update-form" class="btn btn-warning me-1">수정</a>
<form action="/api/board/{{model.id}}/delete" method="post">
<button class="btn btn-danger">삭제</button>
</form>
</div>
{{/model.isOwner}}
<div class="d-flex justify-content-end">
<b>작성자</b> : {{model.username}}
</div>
<!-- 게시글내용 -->
<div>
<h2><b>{{model.title}}</b></h2>
<hr/>
<div class="m-4 p-2">
{{{model.content}}}
</div>
</div>
<!-- 댓글 -->
<div class="card mt-3">
<!-- 댓글등록 -->
<div class="card-body">
<form action="/reply/save" method="post">
<textarea class="form-control" rows="2" name="comment"></textarea>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
<!-- 댓글목록 -->
<div class="card-footer">
<b>댓글리스트</b>
</div>
<div class="list-group">
<!-- 댓글아이템 -->
<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">ssar</div>
<div>댓글1</div>
</div>
<form action="#" method="post">
<button class="btn">🗑</button>
</form>
</div>
</div>
</div>
</div>
{{>layout/footer}}
이로서 일단 댓글 작성과 댓글을 볼 수 있게 되었다.

entity 클래스를 만들어주자.
reply에는 어느 게시판의 댓글인지 알수 있게 board의 id와
누가 댓글을 썼는지 알수있게 user의 id가 필요하다.
그렇기에 fk설정을 해준다.
다하고 서버를 재시작하면 이쁘게 테이블이 생긴다.
인제 더미데이터를 넣어주자

h2로 가서 쿼리들을 만들어보자
SELECT * FROM board_tb bt
inner join user_tb ut on bt.user_id=ut.id;

먼저 board 테이블에 user 테이블을 이너조인하자. board의 userid와 user의 id가 같다는 on절을 정해주자. 모든 게시물을 기준으로 on절에 맞는 유저가 들어가졌다.
SELECT * FROM board_tb bt
inner join user_tb ut on bt.user_id=ut.id
where bt.id=5;

저기다 where 로 조건을 걸어준다. bt는 board테이블의 "별칭" 또는 **"에일리어스(alias)"** 라고 한다.
여러 테이블을 조인할 때 별칭을 사용하면 각 테이블의 필드를 명확하게 구분할 수 있다.
select *
from
(
SELECT bt.id, bt.title, bt.content, ut.username FROM board_tb bt
inner join user_tb ut on bt.user_id=ut.id
where bt.id=5
);

이번엔 내가 필요한 컬럼들을 명시해서 테이블을 뽑아 내보자.

WHERE
절은 SELECT
절이 실행되기 전에 평가되기 때문에, u_id
라는 별칭을 인식하지 못한다
select *
from
(
SELECT bt.id, bt.title, bt.content, ut.id u_id, ut.username FROM board_tb bt
INNER JOIN user_tb ut ON bt.user_id = ut.id
)
where u_id=2;

where 절에 별칭을 꼭 써먹어야겠다면 서브 쿼리를 사용하여 테이블을 만들어 버리게 되면 별칭이 인식이 되어 있는 상태로 만든 뒤 where에 별칭을 사용할 수 있다. 하지만 이건 불필요하게 복잡해 질 수 있다.
SELECT *
FROM
(
SELECT bt.id, bt.title, bt.content, ut.username FROM board_tb bt
INNER JOIN user_tb ut ON bt.user_id = ut.id where bt.id = 5
) t1
inner join reply_tb t2 on t1.id=t2.board_id;;

그렇기에 일을 만들지 말고 where에는 별칭이 아닌 원래의 컬럼명을 넣고, 5번 게시글에 있는 reply들을 조인으로 가져올 수 있다.
SELECT * FROM board_tb bt
INNER JOIN user_tb ut ON bt.user_id = ut.id
INNER JOIN reply_tb rt on bt.id = rt.board_id
INNER JOIN user_tb rut on rut.id = rt.user_id
where bt.id = 5;

결론적으로 이상적인 게시글을 데이터 베이스에서 뽑아낼 때 필요한 쿼리문은 이렇다.
게시글 id가 5번인걸 뽑으려할 때 게시글의 user id와 user의 id를 확인해 작성자를 찾고
해당 게시글에 달려있는 reply들을 조인하여 댓글들을 찾은뒤 댓글의 작성자를 user의 id와 비교해 꺼낸다. 그랬을때 댓글이 3개 있기에 이런식으로 나온다.
SELECT * FROM board_tb bt
INNER JOIN user_tb ut ON bt.user_id = ut.id
INNER JOIN reply_tb rt on bt.id = rt.board_id
INNER JOIN user_tb rut on rut.id = rt.user_id
where bt.id = 2;

아래는 댓글이 없기에 아무것도 안나온다.





package org.example.springv3.board;
import lombok.Data;
import org.example.springv3.reply.Reply;
import org.example.springv3.user.User;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
public class BoardResponse {
@Data
public static class DetailDTO {
private Integer id;
private String title;
private String content;
private Boolean isOwner;
private Integer userId;
private String username;
private List<ReplyDTO> replies = new ArrayList<>();
public DetailDTO(Board board, User sessionUser) {
this.id = board.getId();
this.title = board.getTitle();
this.content = board.getContent();
this.isOwner = false;
if (sessionUser != null) {
if (board.getUser().getId() == sessionUser.getId()) {
isOwner = true; // 권한체크
}
}
this.userId = board.getUser().getId();
this.username = board.getUser().getUsername();
for (Reply reply : board.getReplies()) {
replies.add(new ReplyDTO(reply, sessionUser));
}
}
@Data
public class ReplyDTO {
private Integer id;
private String comment;
private String username;
private Boolean isOwner;
private Timestamp createdAt;
public ReplyDTO(Reply reply, User sessionUser) {
this.id = reply.getId();
this.comment = reply.getComment();
this.username = reply.getUser().getUsername();
this.isOwner = false;
this.createdAt = reply.getCreatedAt();
if (sessionUser != null) {
if (reply.getUser().getId() == sessionUser.getId()) {
isOwner = true;
}
}
}
}
}
}

Share article