7. Spring 게시판 무작정 따라하기
Spring에서 @PathVariable을 활용한 동적 라우팅 및 Mustache를 사용한 데이터 출력 방법
Aug 19, 2024
Spring에서 @PathVariable을 활용한 동적 라우팅 및 Mustache를 사용한 데이터 출력 방법
    @GetMapping("/board/{id}")
    public String detail(@PathVariable("id") Integer id) {
        return "board/detail";
    }
list 에서 클릭된 id 로 매핑되어 이동된다.

이거 덕분에 가능한것
1.1 @PathVariable 란?
Get 요청 → DB select 요청이다
주소에는 규칙이 있음.
(1) /boards?title=제목1
select * from board where title = '제목1'; ← 얘는 거진 컬렉션 타입임(2) /boards?title=제목1&content=내용1
select * from board where title = '제목1' and content='내용1'; (3) /boards/1
select * from board where id = 1;(4) /boards
select * from board(5) /users/1/comment ← user 1이 쓴 코멘트
(6) /boards/2/comments ← 2번 게시글에 있는 코멘트들
- 다음과 같이 쿼리문을 유추 가능하게 된다.
- unique 거나 pk 는 쿼리 스트링으로 받을 수 있지만 아닐 시 PathVariable사용 해야함. (3번)
1.2 boardRepository 쿼리문 작성
 public Board findById(int id) {
        Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
        query.setParameter(1, id);
        Board board = (Board) query.getSingleResult(); // 다운캐스팅 필요
        return board;
    }
id(pk) 로 조회하기 때문에 하이버네이트 까지 갈 필요없이 바로 매핑 가능

1.2.1 findById 단위테스트
    @Test
    public void findById_test() {
        // given
        int id = 1;
        // when
        Board board = boardRepository.findById(id);
        // eye(then : 원래는 검증이 필요함)
        System.out.println(board.getId());
        System.out.println(board.getTitle());
        System.out.println(board.getContent());
    }

더미 데이터가 5건이 있는데 만약 
id = 6을 넣게 되면 다음과 같은 에러가 난다.jakarta.persistence.NoResultException: No result found for query [select * from board_tb where id = ?]
	at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:558)
	at shop.mtcoding.blog.board.BoardRepository.findById(BoardRepository.java:20)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:716)
	at shop.mtcoding.blog.board.BoardRepository$$SpringCGLIB$$0.findById(<generated>)
	at shop.mtcoding.blog.board.BoardRepositoryTest.findById_test(BoardRepositoryTest.java:27)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
에러를 잡아야한다.
 public Board findById(int id) {
        Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
        query.setParameter(1, id);
        try {
            Board board = (Board) query.getSingleResult(); // 다운캐스팅 필요
            return board;
        } catch (Exception e) {
            throw new RuntimeException("게시글 id를 찾을 수 없습니다");
        }
    }try ~ catch 절을 추가하여 적절한 에러 처리를 해줘야함.

throw 를 통해 에러를 비교적 쉽게 관리할 수 있음(본인이 해결하거나, 나를 호출한 메서드에게 넘기거나)
Global Exception Handler 를 통해 한번에 처리할 수 있어진다. (나중에 다룰것)1.3 컨트롤러 수정
   @GetMapping("/board/{id}")
    public String detail(@PathVariable("id") Integer id, HttpServletRequest request) {
        Board board = boardRepository.findById(id);
        request.setAttribute("model", board);
        return "board/detail";
    }1.4 mustache 동적 출력
- 기존
<div class="container p-5">
    
    <!-- 수정삭제버튼 -->
    <div class="d-flex justify-content-end">
        <a href="/board/1/update-form" class="btn btn-warning me-1">수정</a>
        <form>
            <button class="btn btn-danger">삭제</button>
        </form>
    </div>
    <div class="d-flex justify-content-end">
        <b>작성자</b> : 익명
    </div>
    <!-- 게시글내용 -->
    <div>
        <h2><b>제목1</b></h2>
        <hr/>
        <div class="m-4 p-2">
            내용1
        </div>
    </div>
</div>- 변경
<div class="container p-5">
    <!-- 수정삭제버튼 -->
    <div class="d-flex justify-content-end">
        <a href="/board/{{model.id}}/update-form" class="btn btn-warning me-1">수정</a>
        <form action="/board/{{model.id}}/delete" method="post">
            <button class="btn btn-danger">삭제</button>
        </form>
    </div>
    <div class="d-flex justify-content-end">
        <b>작성자</b> : 익명
    </div>
    <!-- 게시글내용 -->
    <div>
        <h2><b>{{model.title}}</b></h2>
        <hr/>
        <div class="m-4 p-2">
            {{model.content}}
        </div>
    </div>
</div>나중에 할 delete 의 경우 
ajaxc , 자바 스크립트 사용하지 않고 내용에 집중하기 위해 post 사용만약  method 가 정삭적으로 delete 면 요청 주소가 아래와 같은게 정석
<form action="/board/{{model.id}}/delete" method="post">
<form action="/board/{{model.id}}" method="delete">결과


스프링부트 게시판 시리즈 v1 - 1. https://inblog.ai/hj/1-spring-게시판-무작정-따라하기-26526 - 2. https://inblog.ai/hj/2-spring-게시판-무작정-따라하기-26560 - 3. https://inblog.ai/hj/3-spring-게시판-무작정-따라하기-26757 - 4. https://inblog.ai/hj/4-spring-게시판-무작정-따라하기-26758 - 5. https://inblog.ai/hj/5-spring-게시판-무작정-따라하기-26934 - 6. https://inblog.ai/hj/6-spring-게시판-무작정-따라하기-26937 - 7. https://inblog.ai/hj/7-spring-게시판-무작정-따라하기-26940 - 8. https://inblog.ai/hj/8-spring-게시판-무작정-따라하기-27065 - 9. https://inblog.ai/hj/9-spring-게시판-무작정-따라하기끝-27066
Share article