댓글 내용
작성자 id
board_id
board_id는 insert 되는 body 데이터이므로
1. 댓글 작성
1. detail.mustache
- boardId와 content가 서버로 넘어간다.
- textarea는 value 속성은 따로 없지만 태그 사이의 값이 value처럼 꺼내진다.

2. Reply
- 생성자를 만들고 @Builder를 걸어서 builder를 만들어준다.
- @Builder는 컬렉션이 있는 클래스에서는 적용이 안된다.
@Builder
public Reply(Integer id, String content, User user, Board board, Timestamp createdAt) {
this.id = id;
this.content = content;
this.user = user;
this.board = board;
this.createdAt = createdAt;
}3. ReplyRequest.SaveDTO
public class ReplyRequest {
@Data
public static class SaveDTO {
private Integer id;
private String content;
private Integer boardId;
public Reply toEntity(User sessionUser, Board board) {
return Reply.builder()
.content(content)
.user(sessionUser)
.board(board)
.build();
}
}
}4. ReplyController
@PostMapping("/reply/save")
public String saveReply(ReplyRequest.SaveDTO reqDTO) {
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) throw new RuntimeException("인증이 필요합니다.");
replyService.save(reqDTO, sessionUser);
return "redirect:/board/" + reqDTO.getBoardId();
}5. ReplyService
@Transactional
public void save(ReplyRequest.SaveDTO reqDTO, User sessionUser) {
Board board = boardRepository.findById(reqDTO.getBoardId());
if (board == null) throw new RuntimeException("Board not found");
Reply reply = reqDTO.toEntity(sessionUser, board);
replyRepository.save(reply);
}6. ReplyRepository
public void save(Reply reply) {
em.persist(reply);
}7. 실행 결과

2. 댓글 삭제
1. detail.mustache

2. ReplyController
@PostMapping("/reply/{id}/delete")
public String deleteReply(@PathVariable("id") int id) {
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) throw new RuntimeException("인증이 필요합니다.");
Integer boardId = replyService.delete(id);
return "redirect:/board/" + boardId;
}3. ReplyService
@Transactional
public Integer delete(Integer id, Integer sessionUserId) {
// 댓글 존재 확인
Reply replyPS = replyRepository.findById(id);
if (replyPS == null) throw new RuntimeException("Reply not found");
// 권한 체크
if (!(replyPS.getUser().getId().equals(sessionUserId))) throw new RuntimeException("User not authorized");
Integer boardId = replyPS.getBoard().getId();
replyRepository.deleteById(id);
return boardId;
}4. ReplyRepository
public Reply findById(int id) {
return em.find(Reply.class, id);
}
public void deleteById(int id) {
Query query = em.createQuery("delete from Reply r where r.id = :id");
query.setParameter("id", id);
query.executeUpdate();
}5. 실행 결과
6. 댓글 삭제 시 replyPS 객체
요청 → 쿼리 날라가고 db에서 삭제 → PC는 건들지X → 동기화X → 응답되면 나중에 사라짐! (em.clear()하면 PC의 찌꺼기 같은.. 거 사라짐)
(em.remove하면 바로 삭제되는데 사용하지 마세용 → PC에서 찾아서 삭제되고 transaction이 끝날때 삭제 쿼리가 db로 날라감)
@Transactional
public Integer delete(Integer id, Integer sessionUserId) {
// 댓글 존재 확인
Reply replyPS = replyRepository.findById(id);
if (replyPS == null) throw new RuntimeException("Reply not found");
// 권한 체크
if (!(replyPS.getUser().getId().equals(sessionUserId))) throw new RuntimeException("User not authorized");
Integer boardId = replyPS.getBoard().getId();
System.out.println("삭제 전 boardId = " + boardId);
replyRepository.deleteById(id);
Integer boardId1 = replyPS.getBoard().getId();
System.out.println("삭제 후 boardId = " + boardId1);
return boardId;
}public void deleteById(Integer id) {
em.createQuery("delete from Reply r where r.id = :id")
.setParameter("id", id)
.executeUpdate();
}
Share article