1️⃣ 비즈니스 파악 - 화면 확인
🔹 비즈니스를 파악해서 어떤 칼럼이 필요한지 파악한다.
🔹 글 작성자 id, 댓글 게시자 id, content, submit버튼,
🔹 insert할 정보는 body로 받는다.

🔹상세페이지 detail.mustache
확인
🔹 컨트롤러에서 처리할 action URL확인 →
/reply/save
🔹 method확인 →
post
요청
🔹 name에 매핑된 키값을 잘 확인해야된다. boardId
, comment
🔹 input태그 hidden
은 눈에 보이지 않지만 id
정보를 같이 보낸다. 🔹앱을 사용할 때는 데이터를 모두 담아서 보내는 것이 좋다.

2️⃣ 테이블 생성
🔹 reply 패키지 생성

🔹 Reply 클래스 생성 → 테이블
🔹 관계를 보면 관계대수가 나온다. → 관계로 ForeignKey와 Driving table을 설정
🔹 Hibernate : ORM 프레임워크 → 공부하자
🔹 reply_tb는 DB에서 조회된 내용을 담기위한 그릇인 Entity이다.
package shop.mtcoding.blog.reply; import jakarta.persistence.*; import lombok.Data; import java.time.LocalDateTime; @Table(name = "reply_tb") @Data @Entity public class Reply { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String comment; private int userId; // user_tb의 PK -> user 외래키 private int boardId; // board_tb의 PK -> board 외래키 private LocalDateTime createdAT; }
서버를 재실행하고 콘솔에서 아래처럼 나오면 정상적으로 작동!

3️⃣ DTO만들기
🔹 아까 view에서 확인했던 name에 매핑된 키값으로 WriteDTO를 만들어 준다.
🔹 BoardId는 페이지에 접속하면 자동으로 식별이 가능하게끔 view에서 input태그로 설정해줬으니 아래 두가지 값을 담을 그릇만 있으면 될 것 같다.
package shop.mtcoding.blog.reply; import lombok.Data; public class ReplyRequest { @Data public static class WriteDTO{ private String comment; private int boardId; }
🔹 DTO에 정보가 잘 담기는지 확인
🔹 DTO를 제대로 확인하기 위해서는 간단한 컨트롤러가 구현이 되어야 한다.
🔹 아까
details.mustache
에서 확인한 action URL 주소 “/reply/save”
post요청을 받을 컨트롤러를 틀정도만 구현해서 DTO를 테스트 한다. @RequiredArgsConstructor @Controller public class ReplyController { // ReplyController를 간단히 구현해보자. @PostMapping("reply/save") public String write (ReplyRequest.WriteDTO requestDTO){ System.out.println(requestDTO); // 테스트 코드 - DTO에 정보가 잘 담기는지 확인 return null; } }
블로그에 로그인하고 아무 게시글이나 들어가서 댓글을 달아보자.

이 에러페이지를 받는 것은 당연하다 당황하지 말자.
중요한 체크 포인트는
🔹 URL주소가 잘 바뀌었는 지 확인 →
/reply/save
🔹 그리고 콘솔을 확인해서 출력이 되었는지 확인한다. 
WriteDTO에 잘 전달되는지 확인완료!

4️⃣ 컨트롤러 구현
이제 컨트롤러를 구현해보자!
🔹 현재 사용자가 세션유저, 즉 로그인된 사용자인지 확인해야된다.
🔹 ReplyRepository 클래스를 같은 패키지에 만들어 놓고 의존성 주입 설정한다.
🔹 반환값으로
“redirect:/board/”+ requestDTO.getBoardId();
설정하여 댓글을 남기면 그 페이지에 머물러 있게 하는 UX를 만들 것이다.package shop.mtcoding.blog.reply; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import shop.mtcoding.blog.user.User; // 댓글 쓰기, 댓글 삭제, 댓글 목록보기 @RequiredArgsConstructor @Controller public class ReplyController { private final HttpSession session; private final ReplyRepository replyRepository; @PostMapping("reply/save") public String write(ReplyRequest.WriteDTO requestDTO) { System.out.println(requestDTO); // 현재 사용자가 세션유저인지 확인 - 로그인된 사람인지 확인 User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { return "redirect:/loginForm"; } // 유효성 검사 -- 이따가 필요하다면 더 구현하기! // 핵심 코드 - 아직 ReplyRepository를 만들지 않았으므로 에러날 것인데 괜찮다. // 그래도 ReplyRepository DI (의존성주입) 설정까지는 끝내놓자. replyRepository.save(requestDTO, sessionUser.getId()); // 핵심 로직 실행후 그 페이지에 그대로 남아있게 하기 위한 코드 return "redirect:/board/" + requestDTO.getBoardId(); } }
5️⃣ ReplyRepository 구현
이제는 기계처럼 하게 되는 것 같다.
🔹
Repository
/ RequiredArgsContructor
🔹 save 메소드 위에 @Transactiona
l 어노테이션을 단다.
🔹 쿼리는 createNavtiveQuery에 다 적지말고 String을 선언해서 세쌍따옴표 안에 넣으면 깔끔하다.package shop.mtcoding.blog.reply; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Repository public class ReplyRepository { private final EntityManager em; @Transactional public void save(ReplyRequest.WriteDTO requestDTO, int id) { String q = """ insert into reply_tb (comment, board_id, user_id, created_at) values (?,?,?, now()) """; Query query = em.createNativeQuery(q); query.setParameter(1,requestDTO.getComment()); query.setParameter(2,requestDTO.getBoardId()); query.setParameter(3, id); query.executeUpdate(); } }