[블로그 만들기] 16. 게시판 구현 : 상세보기

yuzu sim's avatar
Feb 06, 2024
[블로그 만들기] 16. 게시판 구현 : 상세보기

1. detail.mustache 폴더 확인하기

  • board_tb 테이블과 user_tb 조인해야 함
  • 필요한 정보 board_tb : id, title, content
user_tb : id, username
{{> /layout/header}} <div class="container p-5" <!-- 수정삭제버튼 --> <div class="d-flex justify-content-end"> <button class="btn btn-warning me-1">수정</button> <button class="btn btn-danger">삭제</button> </div> <div class="d-flex justify-content-end mt-2"> <b>작성자</b> : ssar </div> <!-- 게시글내용 --> <div> <h2><b>제목자리</b></h2> <hr/> <div class="m-4 p-2"> 내용입니다 </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">cos</div> <div>댓글 내용입니다</div> </div> <form action="/reply/1/delete" method="post"> <button class="btn">🗑</button> </form> </div> <!-- 댓글아이템 --> <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>댓글 내용입니다</div> </div> <form action="/reply/1/delete" method="post"> <button class="btn">🗑</button> </form> </div> </div> </div> </div> {{> /layout/footer}}
notion image
notion image
 

2. BoardController에서 detail로 들어오게 만들기

  • 테이블 URL에 들어오는 값은 PK OR Unique
  • 나머지는 쿼리 스트링으로 적어야 함
  • 주소에 들어가는 모든 것은 where 절에 들어감 / 쿼리는 같음
package shop.mtcoding.blog.board; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import shop.mtcoding.blog.user.User; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { // HttpSession 객체를 참조 private final HttpSession session; private final BoardRepository boardRepository; // DI @GetMapping({"/", "/board"}) public String index(HttpServletRequest request) { User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { System.out.println("로그인 안된 상태입니다"); } else { System.out.println("로그인 된 상태입니다"); } List<Board> boardList = boardRepository.findAll(); request.setAttribute("boardList", boardList); // ("key", value) return "index"; } @GetMapping("/board/saveForm") public String saveForm() { return "board/saveForm"; } // select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ? @GetMapping("/board/1") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {} public String detail() { System.out.println("상세보기 페이지 호출됨"); // 바디 데이터가 없으면 유효성 검사할 필요가 없음 return "board/detail"; } }
notion image
 
package shop.mtcoding.blog.board; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import shop.mtcoding.blog.user.User; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { // HttpSession 객체를 참조 private final HttpSession session; private final BoardRepository boardRepository; // DI @GetMapping({"/", "/board"}) public String index(HttpServletRequest request) { User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { System.out.println("로그인 안된 상태입니다"); } else { System.out.println("로그인 된 상태입니다"); } List<Board> boardList = boardRepository.findAll(); request.setAttribute("boardList", boardList); // ("key", value) return "index"; } @GetMapping("/board/saveForm") public String saveForm() { return "board/saveForm"; } // select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ? @GetMapping("/board/{id}") public String detail(@PathVariable int id, HttpServletRequest request) { System.out.println("상세보기 페이지 호출됨"); System.out.println("id : " + id); // 바디 데이터가 없으면 유효성 검사 안해도 됨 BoardResponse.DetailDTO responseDTO = boardRepository.findById(id); request.setAttribute("board", responseDTO); return "board/detail"; } }
notion image
notion image

3. 응답 DTO 만들기

  • BoardResponse를 만들어서 DetailDTO() 만들기
package shop.mtcoding.blog.board; import lombok.Data; public class BoardResponse { @Data public static class DetailDTO { private int id; private String title; private String content; private int userId; private String username; } }
 

4. findById() 만들어 테스트하기

notion image
package shop.mtcoding.blog.board; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import java.util.List; @RequiredArgsConstructor @Repository public class BoardRepository { private final EntityManager em; // jpa가 제공해줌 // 조회니까 트랜잭션 필요없음 public List<Board> findAll() { // 보드 테이블의 모든 것 가지고 오기 Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class); System.out.println("BoardRepository에 findAll 메서드 호출됨"); return query.getResultList(); // 여러건 } // 이 결과를 리퀘스트에 담고 뷰 화면 가서 뿌리기 public BoardResponse.DetailDTO findById(int idx) { Query query = em.createNativeQuery("select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ?"); query.setParameter(1, idx); Object[] row = (Object[]) query.getSingleResult(); Integer id = (Integer) row[0]; String title = (String) row[1]; String content = (String) row[2]; int userId = (Integer) row[3]; String username = (String) row[4]; System.out.println("id : " + id); System.out.println("title : " + title); System.out.println("content : " + content); System.out.println("userId : " + userId); System.out.println("username : " + username); BoardResponse.DetailDTO responseDTO = new BoardResponse.DetailDTO(); responseDTO.setId(id); responseDTO.setTitle(title); responseDTO.setContent(content); responseDTO.setUserId(userId); responseDTO.setUsername(username); return responseDTO; } }
 

5. DTO에 담아서 화면에 전달하기

package shop.mtcoding.blog.board; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import shop.mtcoding.blog.user.User; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { // HttpSession 객체를 참조 private final HttpSession session; private final BoardRepository boardRepository; // DI @GetMapping({"/", "/board"}) public String index(HttpServletRequest request) { User sessionUser = (User) session.getAttribute("sessionUser"); if (sessionUser == null) { System.out.println("로그인 안된 상태입니다"); } else { System.out.println("로그인 된 상태입니다"); } List<Board> boardList = boardRepository.findAll(); request.setAttribute("boardList", boardList); // ("key", value) return "index"; } @GetMapping("/board/saveForm") public String saveForm() { return "board/saveForm"; } // select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ? @GetMapping("/board/{id}") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {} public String detail(@PathVariable int id, HttpServletRequest request) { System.out.println("id" +id); // 바디 데이터가 없으면 유효성 검사할 필요가 없음 BoardResponse.DetailDTO responseDTO = boardRepository.findById(id); request.setAttribute("board", responseDTO); return "board/detail"; } }
notion image
 

6. 화면에 랜더링하기

  • detail 폴더에서 자바 코드 변수 집어넣기
{{> /layout/header}} <div class="container p-5" <!-- 수정삭제버튼 --> <div class="d-flex justify-content-end"> <button class="btn btn-warning me-1">수정</button> <button class="btn btn-danger">삭제</button> </div> <div class="d-flex justify-content-end mt-2"> <b>작성자</b> : {{board.username}} </div> <!-- 게시글내용 --> <div> <h2><b>{{board.title}}</b></h2> <hr/> <div class="m-4 p-2"> {{board.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">cos</div> <div>댓글 내용입니다</div> </div> <form action="/reply/1/delete" method="post"> <button class="btn">🗑</button> </form> </div> <!-- 댓글아이템 --> <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>댓글 내용입니다</div> </div> <form action="/reply/1/delete" method="post"> <button class="btn">🗑</button> </form> </div> </div> </div> </div> {{> /layout/footer}}
 
notion image
 
notion image
 
notion image
notion image
Share article

Coding_study