[Spring Boot] 48. 스프링부트 블로그 v2 (JPA) (18) 댓글 작성 및 삭제 2

김주희's avatar
Apr 09, 2025
[Spring Boot] 48. 스프링부트 블로그 v2 (JPA) (18) 댓글 작성 및 삭제 2
댓글 내용
작성자 id
board_id
board_id는 insert 되는 body 데이터이므로
 

1. 댓글 작성

1. detail.mustache

  1. boardId와 content가 서버로 넘어간다.
  1. textarea는 value 속성은 따로 없지만 태그 사이의 값이 value처럼 꺼내진다.
notion image
 

2. Reply

  1. 생성자를 만들고 @Builder를 걸어서 builder를 만들어준다.
    1. @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. 실행 결과

notion image
 
 

2. 댓글 삭제

1. detail.mustache

notion image
 

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(); }
notion image
 
Share article

jay0628