사이먼's 코딩노트
[SpringBoot] Detail 링크 및 페이지 추가 / 예외처리 본문
[Detail 링크 및 페이지 추가]
- question list에 대한 페이지까지 구현되었다면, 이번에는 question detail에 관한 링크 연결과 새로운 페이지를 추가해봅시다.
- question detail 페이지에 들어갈 내용은 각 question 데이터의 세부 정보이다.
- 먼저 localhost:8090/question/detail 주소로 이동하는 링크를 만들기 위해선 question_list.html의 a태그를 활용해야 한다.
- 아래와 같이 question_list.html 템플릿에서 코드를 작성한다.
<table border="1">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
<tr th:each="question : ${questionList}">
<td>
<a th:text="${question.id}" th:href="@{|/question/detail/${question.id}|}"></a>
</td>
<td>
<a th:text="${question.subject}" th:href="@{|/question/detail/${question.id}|}"></a>
</td>
<td th:text="${question.createDate}"></td>
</tr>
</tbody>
</table>
- a태그의 href 속성을 사용하여 question의 상세 내용이 담긴 페이지로 이동할 수 있는 링크를 작성한다.
- 제목에 상세 페이지 URL을 연결하기 위해 타임리프의 th:를 반드시 붙혀주고, 이 때 URL은 반드시 @( ) 의 괄호 속에 입력해야 한다.
- 위 코드를 살펴보면 각 question의 id를 보고 상세 페이지로 이동하기 때문에 /question/detail/${question.id}로 작성하고, 타임리프에서는 문자열과 자바 객체의 값을 더할 때 반드시 |로 좌우로 감싸주어야 한다.
- 그렇게 되면 테이블의 번호 열에 있는 id 1번을 클릭하면 /question/detail/1 URL로 이동하게 된다. (2번을 선택하면 /question/detail/2로 이동)
[URL 매핑하기]
- 하지만 지금 상태에서는 해당 주소가 매핑되지도 않았고, question_detail.html 템플릿이 생성되지 않았기 때문에 실제로 링크를 통해 이동해도 404 에러가 발생한다.
- 그렇기 때문에 QuestionController.java 클래스에서 아래와 같이 코드를 작성하여 상세 페이지 URL의 매핑을 해야한다.
@GetMapping("/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id) {
Question q = this.questionService.getQuestion(id);
model.addAttribute("question", q);
return "question_detail";
}
- @GetMapping을 통해 localhost:8090/question/detail/id번호 URL의 매핑을 한다.
- id번호가 항상 1이 아니라 2부터 무한히 증가할 수 있기 때문에 지금처럼 변하는 id값을 얻을 때는 @PathVariable 어노테이션을 사용한다.
- QuestionService를 도입하여 getQuestion(id) 메서드를 호출하여 question의 정보를 q라는 변수에 저장한다.
- getQuestion(id) 메서드는 위 코드에 포함되지 않았지만, findById() 메서드를 사용한 데이터 조회 역할을 한다.
- 다시 말해, findById() 메서드를 통해 question을 조회하고 Model 객체에 question이라는 이름으로 저장한다.
- 마지막으로 detail() 메서드의 return 값을 question_detail로 반환하고, 이제는 question_detail 템플릿을 새로 생성해야한다.
[question_detail.html 템플릿 생성]
- 아래는 question_detail.html 템플릿을 생성하고 작성된 코드이다.
<h2>
<h3 th:text="${question.id}"></h3>
<div th:text="${question.subject}"></div>
<div th:text="${question.content}"></div>
</h2>
- QuestionController.java 클래스의 detail() 메서드에서 Model 객체에 question 이라는 이름으로 Question 객체를 저장했기 때문에 위와 같이 question.id, question.subject, question.content 로 작성하여 해당하는 question의 세부 내용을 가져온다.
- 다시 로컬 서버를 실행하여 localhost:8090/question/list에 접속해서 링크를 통해 localhost:8090/question/detail/1로 접속하게 되면 아래와 같이 1번 question 데이터의 상세 내용을 확인할 수 있다.
[예외처리 적용]
- 만약 question 테이블에 아무런 데이터도 없을 경우를 대비해서 예외 처리를 해주는 것이 좋다.
- 아래 코드는 id별로 question 데이터를 조회하는 findById() 메서드가 포함된 QuestionService.java 클래스의 getQuestion() 메서드 부분이고, 해당 메서드 내에서 Exception을 적용하여 예외처리를 해보려한다.
public Question getQuestion(Integer id) {
Optional<Question> oq = this.questionRepository.findById(id);
if(oq.isEmpty()) throw new DataNotException("question not found");
return oq.get();
}
- 조건문을 통해 question 데이터가 존재하는지 검사하는 과정이 필요하고, isPresent() 메서드를 사용해도 되지만, 코드를 간소화하기위해 isEmpty() 메서드를 사용하여 조건을 만들었다.
- 만약 데이터가 없다면, 예외 클래스인 DataNotFoundException이 실행되면서 'question not found' 라는 문자열이 출력되도록 했지만, 사실 DataNotFoundException 이라는 클래스는 존재하지 않기 때문에 직접 예외처리 클래스를 추가해야 한다.
- 아래는 DataNotFoundException.java 클래스를 새로 생성하여 작성된 코드이다.
package com.sbs.sbb;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "entity not found")
public class DataNotException extends RuntimeException {
public DataNotException(String msg) {
super(msg);
}
}
- DataNotFoundException은 DB에서 특정 엔티티 또는 데이터를 찾을 수 없을 때 발생시키는예외 클래스로 만들었다.
- 이 예외가 발생하면 스프링 부트는 설정된 HTTP 상태 코드인 HttpStatus.NOT_FOUND와 이유(reason)를 포함한 응답을 생성하여 클라이언트에 반환하게 된다. 여기서는 404 에러를 반환하도록 했다.
- RuntimeException 클래스를 상속하는 이유는 사용자 정의의 예외 클래스를 정의하는 방법 중 하나이기 때문이다.
- DataNotException() 메서드의 매개변수인 msg는 QuestionServcie.java 에서 작성한 question not found를 의미하고, super()를 사용하여 부모 클래스의 생성자를 호출하여 메시지를 출력한다.
반응형
'Java > SpringBoot' 카테고리의 다른 글
[SpringBoot] Answer 저장 및 출력 / 스타일시트 적용 (0) | 2024.05.09 |
---|---|
[SpringBoot] Prefix 적용 / Form 만들기 (0) | 2024.05.09 |
[SpringBoot] Thymeleaf / 데이터 전달 및 랜더링 / Redirect (0) | 2024.05.08 |
[SpringBoot] Repository로 DB 관리하기(3) (0) | 2024.05.07 |
[SpringBoot] Repository로 DB 관리하기(2) (0) | 2024.05.07 |