02J. ์ง๋ฌธ ์์ธ
02J. ์ง๋ฌธ ์์ธ ๊ด๋ จ
์ด๋ฒ ์ฅ์์๋ ์ง๋ฌธ ๋ชฉ๋ก์ ์ด์ด ์ง๋ฌธ ์์ธ ๊ธฐ๋ฅ์ ์ถ๊ฐํด ๋ณด์.
์ง๋ฌธ ์์ธ ๋งํฌ ์ถ๊ฐํ๊ธฐ
๋จผ์ ์ง๋ฌธ ๋ชฉ๋ก์ ์ ๋ชฉ์ ํด๋ฆญํ์๋ ์์ธํ๋ฉด์ด ํธ์ถ๋๋๋ก ์ ๋ชฉ์ ๋งํฌ๋ฅผ ์ถ๊ฐํ์. ์ง๋ฌธ ๋ชฉ๋ก ํ ํ๋ฆฟ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ์.
ํ์ผ๋ช :
/sbb/src/main/resources/templates/
question_list.html
<table>
<thead>
<tr>
<th>์ ๋ชฉ</th>
<th>์์ฑ์ผ์</th>
</tr>
</thead>
<tbody>
<tr th:each="question, index : ${questionList}">
<td>
<a th:href="@{|/question/detail/${question.id}|}" th:text="${question.subject}"></a>
</td>
<td th:text="${question.createDate}"></td>
</tr>
</tbody>
</table>
์ ๋ชฉ์ <td>
์๋ฆฌ๋จผํธ์ ํ
์คํธ๋ก ์ถ๋ ฅํ๋ ๊ฒ์์ ๋งํฌ๋ก ๋ณ๊ฒฝํ๋ค. ํ์๋ฆฌํ์์ ๋งํฌ์ ์ฃผ์๋ th:href
์์ฑ์ ์ฌ์ฉํ๋ค. ํ์๋ฆฌํ์์ th:href
์ฒ๋ผ URL ์ฃผ์๋ฅผ ๋ํ๋ผ๋๋ ๋ฐ๋์ @{
๋ฌธ์์ }
๋ฌธ์ ์ฌ์ด์ ์
๋ ฅํด์ผ ํ๋ค. ๊ทธ๋ฆฌ๊ณ URL ์ฃผ์๋ ๋ฌธ์์ด /question/detail/
๊ณผ ${question.id}
๊ฐ์ด ์กฐํฉ๋์ด /question/detail/${question.id}
๋ก ๋ง๋ค์ด์ก๋ค. ์ด๋ ์ข์ฐ์ |
๋ฌธ์์์ด ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
<a th:href="@{/question/detail/${question.id}}" th:text="${question.subject}"></a>
/question/detail/
๊ณผ ๊ฐ์ ๋ฌธ์์ด๊ณผ ${question.id}
์ ๊ฐ์ ์๋ฐ ๊ฐ์ฒด์ ๊ฐ์ ๋ํ ๋๋ ๋ฐ๋์ ๋ค์์ฒ๋ผ |
๊ณผ |
๊ธฐํธ๋ก ์ข์ฐ๋ฅผ ๊ฐ์ธ ์ฃผ์ด์ผ ํ๋ค.
<a th:href="@{|/question/detail/${question.id}|}" th:text="${question.subject}"></a>
ํ์๋ฆฌํ๋ ๋ฌธ์์ด์ ์ฐ๊ฒฐ(concatenation)ํ ๋
|
๋ฌธ์๋ฅผ ์ฌ์ฉํ๋ค.
์ง๋ฌธ ์์ธ ์ปจํธ๋กค๋ฌ ๋ง๋ค๊ธฐ
์ด์ ์ง๋ฌธ ๋ชฉ๋ก ํ์ด์ง์ ์ ์ํ์ฌ ๋งํฌ๋ฅผ ํด๋ฆญํด ๋ณด์.
http://localhost:8080/question/detail/2
URL ์์ฒญ์ ๋ํ ๋งคํ์ด ์๊ธฐ ๋๋ฌธ์ 404(Page not found) ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ง๋ฌธ ์์ธ ํ์ด์ง์ ๋ํ URL ๋งคํ์ QuestionController
์ ๋ค์๊ณผ ๊ฐ์ด ์ถ๊ฐํ์.
ํ์ผ๋ช :
/sbb/src/main/java/com/mysite/sbb/question/
QuestionController.java
// (... ์๋ต ...)
import org.springframework.web.bind.annotation.PathVariable;
// (... ์๋ต ...)
public class QuestionController {
(... ์๋ต ...)
@GetMapping(value = "/question/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id) {
return "question_detail";
}
}
์์ฒญ URL http://localhost:8080/question/detail/2
์ ์ซ์ 2์ฒ๋ผ ๋ณํ๋ id ๊ฐ์ ์ป์ ๋์๋ ์์ ๊ฐ์ด @PathVariable
์ ๋ํ
์ด์
์ ์ฌ์ฉํด์ผ ํ๋ค. ์ด ๋ @GetMapping(value = "/question/detail/{id}")
์์ ์ฌ์ฉํ id
์ @PathVariable("id")
์ ๋งค๊ฐ๋ณ์ ์ด๋ฆ์ด ๋์ผํด์ผ ํ๋ค.
์์ ๊ฐ์ด ์์ ํ๊ณ ๋ค์ URL์ ํธ์ถํ๋ฉด ์ด๋ฒ์๋ 404 ๋์ 500 ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒ์ด๋ค. ์๋ํ๋ฉด ์๋ต์ผ๋ก ๋ฆฌํดํ question_detail
ํ
ํ๋ฆฟ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ค์๊ณผ ๊ฐ์ด question_detail.html
ํ์ผ์ ์ ๊ท๋ก ์์ฑํ์.
ํ์ผ๋ช :
/sbb/src/main/resources/templates/
question_detail.html
<h1>์ ๋ชฉ</h1>
<div>๋ด์ฉ</div>
์๋น์ค
์ด์ ํ๋ฉด์ ์ถ๋ ฅํ "์ ๋ชฉ", "๋ด์ฉ" ๋ฌธ์์ด ๋์ ๋ฐ์ดํฐ์ ์ค์ ์ ๋ชฉ๊ณผ ๋ด์ฉ์ ์ถ๋ ฅํด ๋ณด์. Question
๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ธฐ ์ํด์ QuestionService
๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ์.
ํ์ผ๋ช :
/sbb/src/main/java/com/mysite/sbb/question/
QuestionService.java
// (... ์๋ต ...)
import java.util.Optional;
import com.mysite.sbb.DataNotFoundException;
// (... ์๋ต ...)
public class QuestionService {
// (... ์๋ต ...)
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 ๊ฐ์ผ๋ก Question
๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ getQuestion
๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค. ๋ฆฌํฌ์งํฐ๋ฆฌ๋ก ์ป์ Question
๊ฐ์ฒด๋ Optional
๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ด isPresent ๋ฉ์๋๋ก ํด๋น ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๋์ง ๊ฒ์ฌํ๋ ๋ก์ง์ด ํ์ํ๋ค. ๋ง์ฝ id ๊ฐ์ ํด๋นํ๋ Question
๋ฐ์ดํฐ๊ฐ ์์ ๊ฒฝ์ฐ์๋ DataNotFoundException
์ ๋ฐ์์ํค๋๋ก ํ๋ค. DataNotFoundException
ํด๋์ค๋ ์์ง ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒ์ด๋ค. DataNotFoundException
ํด๋์ค๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ์.
ํ์ผ๋ช :
/sbb/src/main/java/com/mysite/sbb/
DataNotFoundException.java
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
์ RuntimeException
์ ์์ํ์ฌ ๋ง๋ค์๋ค. ๋ง์ฝ DataNotFoundException
์ด ๋ฐ์ํ๋ฉด @ResponseStatus
์ ๋ํ
์ด์
์ ์ํด 404 ์ค๋ฅ(HttpStatus.NOT_FOUND
)๊ฐ ๋ํ๋ ๊ฒ์ด๋ค.
๊ทธ๋ฆฌ๊ณ QuestionController
์์ QuestionService
์ getQuestion
๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ Question
๊ฐ์ฒด๋ฅผ ํ
ํ๋ฆฟ์ ์ ๋ฌํ ์ ์๋๋ก ๋ค์๊ณผ ๊ฐ์ด ์์ ํ์.
ํ์ผ๋ช :
/sbb/src/main/java/com/mysite/sbb/question/
QuestionController.java
// (... ์๋ต ...)
public class QuestionController {
// (... ์๋ต ...)
@GetMapping(value = "/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";
}
}
ํ ํ๋ฆฟ
QuestionController
์ detail
๋ฉ์๋์์ Model
๊ฐ์ฒด์ "question" ์ด๋ผ๋ ์ด๋ฆ์ผ๋ก Question
๊ฐ์ฒด๋ฅผ ์ ์ฅํ์ผ๋ฏ๋ก ํ
ํ๋ฆฟ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ ์ ์๋ค.
ํ์ผ๋ช :
/sbb/src/main/resources/templates/
question_detail.html
<h1 th:text="${question.subject}"></h1>
<div th:text="${question.content}"></div>
์ง๋ฌธ ์์ธ ํ์ธํ๊ธฐ
์ด์ ๋ค์ ์ง๋ฌธ ์์ธ ํ์ด์ง๋ฅผ ์์ฒญํด ๋ณด์.
์กฐํํ Question
๋ฐ์ดํฐ์ ์ ๋ชฉ๊ณผ ๋ด์ฉ์ด ํ๋ฉด์ ์ ์ถ๋ ฅ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ด๋ฒ์๋ ๋ค์์ฒ๋ผ 33๊ณผ ๊ฐ์ ์กด์ฌํ์ง ์๋ id ๊ฐ์ผ๋ก ํ์ด์ง๋ฅผ ์์ฒญํด ๋ณด์.
http://localhost:8080/question/detail/33
URL ํ๋ฆฌํฝ์ค(prefix)
๋ค์์ผ๋ก ๋์ด๊ฐ๊ธฐ ์ ์ QuestionController
์ URL ๋งคํ์ ์ ์ ์ดํด๋ณด์. ํ์ฌ QuestionController
์๋ ๋ค์ 2๊ฐ์ URL ๋งคํ์ด ์๋ค.
@GetMapping("/question/list")
@GetMapping(value = "/question/detail/{id}")
URL ๋งคํ์ value ๋งค๊ฐ๋ณ์๋ ์๋ตํ ์ ์๋ค.
URL์ ํ๋ฆฌํฝ์ค๊ฐ ๋ชจ๋ /question
์ผ๋ก ์์ํ๋ค๋ ๊ฒ์ ์์ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ํด๋์ค๋ช
์์ @RequestMapping("/question")
์ ๋ํ
์ด์
์ ์ถ๊ฐํ๊ณ ๋ฉ์๋ ๋จ์์์๋ /question
๋ฅผ ์๋ตํ ๊ทธ ๋ท ๋ถ๋ถ๋ง์ ์ ์ผ๋ฉด ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด QuestionController
๋ฅผ ์์ ํด ๋ณด์.
ํ์ผ๋ช :
/sbb/src/main/java/com/mysite/sbb/question/
QuestionController.java
// (... ์๋ต ...)
import org.springframework.web.bind.annotation.RequestMapping;
// (... ์๋ต ...)
@RequestMapping("/question")
@RequiredArgsConstructor
@Controller
public class QuestionController {
private final QuestionService questionService;
@GetMapping("/list")
public String list(Model model) {
(... ์๋ต ...)
}
@GetMapping(value = "/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id) {
(... ์๋ต ...)
}
}
list
๋ฉ์๋์ URL ๋งคํ์ /list
์ด์ง๋ง ํด๋์ค์ /question
์ด๋ผ๋ URL ๋งคํ์ด ์๊ธฐ ๋๋ฌธ์ /question
+ /list
๊ฐ ๋์ด ์ต์ข
์ ์ธ URL ๋งคํ์ /question/list
๊ฐ ๋๋ค. ์์ ๊ฐ์ด ์์ ํ๋ฉด ๊ธฐ์กด๊ณผ ์์ ํ ๋์ผํ ๊ธฐ์ค์ผ๋ก URL ๋งคํ์ด ์ด๋ฃจ์ด ์ง๋ค. ๋ค๋ง, ์์ผ๋ก QuestionController
์์ ์ฌ์ฉํ๋ URL ๋งคํ์ ํญ์ /question
์ผ๋ก ์์ํด์ผ ํ๋ ๊ท์น์ด ์๊ธด ๊ฒ์ด๋ค.
์ปจํธ๋กค๋ฌ์ ํด๋์ค ๋จ์์ URL ๋งคํ์ ํ์์ฌํญ์ด ์๋๋ค. ์ปจํธ๋กค๋ฌ์ ์ฑ๊ฒฉ์ ๋ง๊ฒ ์ฌ์ฉํ๋ฉด ๋๋ค.