
@GetMapping("/detail/{id}") + @PathVariable๋ก URL์ id๋ฅผ ๋ฐ์ ๋จ๊ฑด ์์ธ ์ฒ๋ฆฌitemRepository.findById(id)๋ Optional โ ๋ถ์ฌ ์ ๋ฆฌ๋ค์ด๋ ํธ/404๋ก ์์ ์ฒ๋ฆฌtemplates/error.html๋ง ๋ฌ๋ ๊ธฐ๋ณธ ์๋ฌ ํ์ด์ง ์ปค์คํ
๊ฐ๋ฅ/detail/{id}๋ก ๋ค์ด์จ ์์ฒญ๋ณ๋ก ๊ฐ ์ํ์ ์์ธ ํ๋ฉด ๋ ๋๋ง| ๊ฐ๋ | ์ค๋ช |
|---|---|
@PathVariable | /detail/{id} ๊ฒฝ๋ก ๋ณ์ ๊ฐ์ ๋ฉ์๋ ์ธ์๋ก ๋ฐ์ธ๋ฉ |
Optional<T> | ๊ฐ ๋ถ์ฌ ๊ฐ๋ฅ์ฑ ํํ(NPE ๋ฐฉ์ง). isPresent, orElseThrow ๋ฑ ์ ๊ณต |
Model | ์ปจํธ๋กค๋ฌ โ ํ ํ๋ฆฟ์ผ๋ก ๋ฐ์ดํฐ ์ ๋ฌ ์ปจํ ์ด๋ |
th:href, @{} | ํ์๋ฆฌํ์์ ์์ ํ URL ์์ฑ |
error.html | templates/error.html์ด ์กด์ฌํ๋ฉด ์คํ๋ง์ด ์๋ฌ ์ ์ด ๋ทฐ๋ฅผ ๋ ๋ |
๐ src/main/java/com/apple/shop/ItemController.java
package com.apple.shop;
import com.apple.shop.item.Item;
import com.apple.shop.item.ItemRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Controller
public class ItemController {
private final ItemRepository itemRepository;
public ItemController(ItemRepository itemRepository) {
this.itemRepository = itemRepository;
}
@GetMapping("/detail/{id}")
public String detail(@PathVariable Long id, Model model) {
var optional = itemRepository.findById(id); // Optional<Item>
if (optional.isPresent()) {
model.addAttribute("data", optional.get());
return "detail"; // templates/detail.html
} else {
return "redirect:/list"; // or return "error/404" ๋ฑ
}
}
}
{id} ๊ฒฝ๋ก์ ์ซ์๋ฅผ @PathVariable Long id๋ก ๋ฐ์ findById(id) ๊ฒฐ๊ณผ๊ฐ ์์ ์ ์์ผ๋ฏ๋ก Optional ์์ ์ฒ๋ฆฌ model.addAttribute("data", ...) โ ๋ทฐ์์ ${data.*}๋ก ์ ๊ทผ๐ src/main/resources/templates/detail.html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${data.title}">์์ธํ์ด์ง</title>
<style>
.detail { text-align: center; }
.detail img { max-width: 30%; display: block; margin: auto; }
</style>
</head>
<body>
<div th:replace="~{nav.html :: navbar}"></div>
<div class="detail">
<h4>์์ธํ์ด์ง</h4>
<img src="https://placehold.co/300" alt="thumbnail">
<h4 th:text="${data.title}">์ํ๋ช
</h4>
<p th:text="${#numbers.formatInteger(data.price, 0, 'COMMA') + '์'}">๊ฐ๊ฒฉ</p>
</div>
</body>
</html>
${data.title}, ${data.price} ๋ฑ์ผ๋ก ์ปจํธ๋กค๋ฌ์์ ๋๊ธด ๊ฐ ์ถ๋ ฅ th:replace๋ก ๊ณตํต Navbar ์ฝ์
๐ src/main/resources/templates/list.html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>๋ชฉ๋ก</title></head>
<body>
<div th:replace="~{nav.html :: navbar}"></div>
<h3>์ํ ๋ชฉ๋ก</h3>
<div class="card" th:each="i : ${items}">
<img src="https://placehold.co/300">
<h4 th:text="${i.title}">์ํ๋ช
</h4>
<!-- ๋ฐฉ๋ฒ 1: ๋ฌธ์์ด ์ฐ๊ฒฐ -->
<a th:href="@{'/detail/' + ${i.id}}">์์ธ๋ณด๊ธฐ</a>
<!-- ๋ฐฉ๋ฒ 2: ํ
ํ๋ฆฟ ๋ฆฌํฐ๋ด ์คํ์ผ(๊ฐ๋
์ฑ โ) -->
<!-- <a th:href="@{|/detail/${i.id}|}">์์ธ๋ณด๊ธฐ</a> -->
<p th:text="${#numbers.formatInteger(i.price, 0, 'COMMA') + '์'}">๊ฐ๊ฒฉ</p>
</div>
</body>
</html>
/detail/1๋ก ๊ฐ๋ ์ค์๋ฅผ ๋ฐฉ์ง โ ์ํ๋ณ id๋ก ๋งํฌ ์์ฑ @{} ๊ตฌ๋ฌธ์ ์ปจํ
์คํธ ๋ฃจํธ๊น์ง ๊ณ ๋ คํด ์์ ํ URL ์์ฑ/detail/abc)abc๋ฅผ Long์ผ๋ก ๋ณํํ์ง ๋ชปํด 400/500 ์๋ฌ ๋ฐ์ ๊ฐ๋ฅ /detail/9999)findById ๊ฒฐ๊ณผ๊ฐ ๋น์ด์์ โ ๋ฆฌ๋ค์ด๋ ํธ or 404 ํ์ด์ง ๋ ๋๐ src/main/resources/templates/error.html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค</title></head>
<body>
<div th:replace="~{nav.html :: navbar}"></div>
<h2>๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</h2>
<p th:text="'Status: ' + ${status}"></p>
<p th:text="'Error: ' + ${error}"></p>
<p th:text="'Path: ' + ${path}"></p>
<p th:text="${message}"></p>
<!-- ์ด์ ํ๊ฒฝ์์ exception ๋
ธ์ถ์ ์ง์ -->
</body>
</html>
templates/error.html์ด ์กด์ฌํ๋ฉด ์๋ฌ ์ ์๋ ๋ ๋ ${status}, ${error}, ${path}, ${message} ๋ณ์ ํ์ฉ ํ์ฅ: ์ํฉ๋ณ ํ์ด์ง๋ฅผ ๋ถ๋ฆฌํ๊ณ ์ถ๋ค๋ฉด
templates/error/404.html,templates/error/500.html์ ์ถ๊ฐํ๋ฉด ์ํ ์ฝ๋์ ๋ง์ถฐ ์๋ ๋งคํ๋จ.
| ํค์๋ | ํ ์ค ์์ฝ |
|---|---|
@PathVariable | ๊ฒฝ๋ก ๋ณ์๋ก ์์ธ ๋ผ์ฐํ |
Optional | ๊ฐ ๋ถ์ฌ ์์ ์ฒ๋ฆฌ ์ปจํ ์ด๋ |
Model | ํ ํ๋ฆฟ์ ๋ฐ์ดํฐ ์ ๋ฌ |
th:href @{} | ์์ ํ ๋งํฌ ์์ฑ |
error.html | ์คํ๋ง + ํ์๋ฆฌํ ๊ธฐ๋ณธ ์๋ฌ ํ์ด์ง ์ปค์คํ |
Optional๋ก ์์์ ๋จผ์ ์ค๊ณํ๋ฉด ์์ธ๊ฐ ๋จ์ํด์ง๋ค.