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