#10 : 질문 상세
01. 질문 상세 링크 추가하기
- question_list.html 수정
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<thead>
<tr>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
<tr th:each="question, index : ${qList}">
<td>
<a th:href="@{|/question/detail/${question.id}|}"
th:text="${question.subject}"></a>
</td>
<td th:text="${question.createDate}"></td>
</tr>
</tbody>
</table>
</body>
</html>
* th:href="" : 링크의 주소를 명시하는 속성, 타임리프에서 URL 주소를 나타낼 때는 반드시 @{}의 형식을 따른다.
/question/detail/ 문자열과 ${question.id}와 같은 값을 조합할 때는 | 기호로 감싸주어야 오류가 나지 않는다.
(타임리프에서는 문자열 연결(concatenation)에 |를 사용한다.)

[ 오류 기록 01 ]
* 오류 내용 : 테스트 코드 실행 안됨
> No tests found for given includes: [com.mysite.sbb.SbbApplicationTests](--tests filter)
* 오류 해결 :
아래 코드를
import org.junit.Test;
이렇게 수정
import org.junit.jupiter.api.Test;
정상적으로 작동 확인!
[ 오류 기록 02 ]
* 오류 내용 : 오류 코드 500, html의 경로도 모두 옳은데 페이지가 표시되지 않음.

* 오류 해결 :
suffix, preffix 설정 다 추가하고 삭제하고 다 바꾸어 보았는데도 안되었는데🥺
우연히 발견한 블로그에서 해당 문장을 주석처리 후 해결이 되었다는 걸 발견했다.
application.properties의 아래 부분을 주석처리
#spring.thymeleaf.prefix=file:src/main/resources/templates/
정상적으로 실행된다!
02. 질문 상세 컨트롤러 만들기
- QuestionController.java 수정
package com.mysite.sbb.controller;
import com.mysite.sbb.entity.Question;
import com.mysite.sbb.service.QuestionService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class QuestionController {
private final QuestionService questionService;
@GetMapping("/question/list")
public String list(Model model) {
List<Question> qList = this.questionService.getList();
model.addAttribute("qList",qList);
return "question_list";
}
@GetMapping("/question/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id) {
return "question_detail";
}
}
* detail/ 이후의 숫자가 변해야하기 때문에 {id}로 받아 id라는 변수로 해당 값을 저장한다, 요청 매핑명과 @PathVariable의 매개변수의 이름이 같아야한다.
- question_detail.html 생성
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>제목</h1>
<div>내용</div>
</body>
</html>

03.서비스
- 실제 제목과 내용을 조회하기 위해 QuestionService.java 수정
package com.mysite.sbb.service;
import com.mysite.sbb.entity.Question;
import com.mysite.sbb.repository.QuestionRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import com.mysite.sbb.DataNotFoundException;
@Service
@RequiredArgsConstructor
public class QuestionService {
private final QuestionRepository questionRepository;
public List<Question> getList(){
return this.questionRepository.findAll();
}
public Question getQuestion(Integer id){
Optional<Question> question = this.questionRepository.findById(id);
if(question.isPresent()){
return question.get();
}else{
throw new DataNotFoundException("question not found");
}
}
}
* id로 질문을 조회하는 getQuestion 메서드
* Question 객체는 Optional 객체이기 때문에 위와 같이 isPresent 메서드로 해당 데이터가 존재하는지 검사하는 과정 필요
- 질문 데이터가 없는 경우 DataNotFoundException 발생하도록 클래스 생성
package com.mysite.sbb;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value= HttpStatus.NOT_FOUND, reason = "entity not found")
public class DataNotFoundException extends RuntimeException{
private static final long serialVersionUID = 1L;
public DataNotFoundException(String message){
super(message);
}
}
* DataNotFoundException이 발생하면 @ResposeStatus에 의해 404에러 페이지가 나타난다.
- 컨트롤러에서 서비스단에서 가져온 Question 객체를 전달할 수 있도록 QuestionController.java 수정
package com.mysite.sbb.controller;
import com.mysite.sbb.entity.Question;
import com.mysite.sbb.service.QuestionService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class QuestionController {
private final QuestionService questionService;
@GetMapping("/question/list")
public String list(Model model) {
List<Question> qList = this.questionService.getList();
model.addAttribute("qList",qList);
return "question_list";
}
@GetMapping("/question/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id) {
Question question = this.questionService.getQuestion(id);
model.addAttribute("question",question);
return "question_detail";
}
}
04.템플릿
- 모델 객체에 question으로 저장한 객체를 템플릿에도 적용하여 question_detail.html 수정
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${question.subject}"></h1>
<div th:text="${question.content}"></div>
</body>
</html>
05. 질문 상세 확인하기
- 존재하지 않는 값으로 출력 확인

question not found가 출력된 것을 확인
- 존재하는 값으로 출력 확인

정상적인 출력 확인
06. URL 프리픽스
- @RequestMapping으로 중복되는 요청명 명시 가능
package com.mysite.sbb.controller;
import com.mysite.sbb.entity.Question;
import com.mysite.sbb.service.QuestionService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/question")
@RequiredArgsConstructor
public class QuestionController {
private final QuestionService questionService;
@GetMapping("/list")
public String list(Model model) {
List<Question> qList = this.questionService.getList();
model.addAttribute("qList",qList);
return "question_list";
}
@GetMapping("/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id) {
Question question = this.questionService.getQuestion(id);
model.addAttribute("question",question);
return "question_detail";
}
}
'T-I-L > [책] 요약&정리' 카테고리의 다른 글
| [점프 투 스프링부트] 2장 스프링부트의 기본 요소(템플릿상속, 질문등록과폼, 공통템플릿) - 2023. 08. 21. (0) | 2023.08.21 |
|---|---|
| [점프 투 스프링부트] 2장 스프링부트의 기본 요소(답변등록,부트스트랩) - 2023. 08. 18 (0) | 2023.08.18 |
| [점프 투 스프링부트] 2장 스프링부트의 기본 요소(질문목록, 템플릿, 서비스) - 2023. 08. 16 (0) | 2023.08.16 |
| [점프 투 스프링부트] 2장 스프링부트의 기본 요소(엔티티,리포지토리) - 2023. 08. 14 (0) | 2023.08.14 |
| [점프 투 스프링부트] 2장 스프링부트의 기본 요소(프로젝트구성, 컨트롤러, JPA) - 2023. 08. 11 (0) | 2023.08.12 |
