[Spring] 7.์คํ๋ง MVC - ์น ํ์ด์ง ๋ง๋ค๊ธฐ
1. ํ๋ก์ ํธ ์์ฑ
ํ์ผ์ฐธ๊ณ
2. ์๊ตฌ์ฌํญ ๋ถ์
์ํ ๋๋ฉ์ธ ๋ชจ๋ธ
- ์ํ ID
- ์ํ๋ช
- ๊ฐ๊ฒฉ
- ์๋
์ํ ๊ด๋ฆฌ ๊ธฐ๋ฅ
- ์ํ ๋ชฉ๋ก
- ์ํ ์์ธ
- ์ํ ๋ฑ๋ก
- ์ํ ์์
3. ์ํ ๋๋ฉ์ธ ๊ฐ๋ฐ
์ํ ๊ฐ์ฒด
@Data
public class Item {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
* @Data(๋กฌ๋ณต)๋ ํต์ฌ ๋๋ฉ์ธ ๋ชจ๋ธ์ ์ฌ์ฉํ๊ธฐ ์ํํจ (getter setter๋ง ์ถ์ฒ)
์์ดํ ์ ์ฅ์
@Repository
public class ItemRepository {
private static final Map<Long, Item> store = new HashMap<>(); //static ์ฌ์ฉ private static long sequence = 0L; //static ์ฌ์ฉ
public Item save(Item item) {
item.setId(++sequence);
store.put(item.getId(), item);
return item;
}
public Item findById(Long id) {
return store.get(id);
}
public List<Item> findAll() {
return new ArrayList<>(store.values());
}
public void update(Long itemId, Item updateParam) {
Item findItem = findById(itemId);
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
public void clearStore() {
store.clear();
}
}
4. ์ํ ์๋น์ค HTML
๋ถํธ์คํธ๋ฉ
- HTML ํธ๋ฆฌ ๊ฐ๋ฐ ์ํด ์ฌ์ฉ
5. ์ํ ๋ชฉ๋ก - ํ์๋ฆฌํ
BasicItemController
@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {
private final ItemRepository itemRepository;
@GetMapping
public String items(Model model) {
List<Item> items = itemRepository.findAll();
model.addAttribute("items", items);
return "basic/items";
}
/**
* ํ
์คํธ์ฉ ๋ฐ์ดํฐ ์ถ๊ฐ
*/
@PostConstruct
public void init() {
itemRepository.save(new Item("testA", 10000, 10));
itemRepository.save(new Item("testB", 20000, 20));
}
}
@RequiredArgsConstructor : final ์ด ๋ถ์ ๋ฉค๋ฒ๋ณ์๋ง ์ฌ์ฉํด์ ์์ฑ์๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด์ค๋ค.
public BasicItemController(ItemRepository itemRepository) {
this.itemRepository = itemRepository;
}
์ํ ๋ชฉ๋ก view
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css"
th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>์ํ ๋ชฉ๋ก</h2> </div>
<div class="row">
<div class="col">
<button class="btn btn-primary float-end"
onclick="location.href='addForm.html'"
th:onclick="|location.href='@{/basic/items/add}'|" type="button">์ํ ๋ฑ๋ก</button>
</div>
</div>
<hr class="my-4">
<div>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>์ํ๋ช
</th>
<th>๊ฐ๊ฒฉ</th>
<th>์๋</th> </tr>
</thead>
<tbody>
<tr th:each="item : ${items}">
<td><a href="item.html" th:href="@{/basic/items/{itemId} (itemId=${item.id})}" th:text="${item.id}">ํ์id</a></td>
<td><a href="item.html" th:href="@{|/basic/items/${item.id}|}" th:text="${item.itemName}">์ํ๋ช
</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
</tr>
</tbody>
</table>
</div>
</div> <!-- /container -->
</body>
</html>
6. ์ํ ์์ธ
BasicItemController์ ์ถ๊ฐ
@GetMapping("/{itemId}")
public String item(@PathVariable Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "basic/item";
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css"
th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<style>
.container {
max-width: 560px;
} </style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>์ํ ์์ธ</h2> </div>
<div>
<label for="itemId">์ํ ID</label>
<input type="text" id="itemId" name="itemId" class="form-control"
value="1" th:value="${item.id}" readonly>
</div> <div>
<label for="itemName">์ํ๋ช
</label>
<input type="text" id="itemName" name="itemName" class="form-control"
value="์ํA" th:value="${item.itemName}" readonly> </div>
<div>
<label for="price">๊ฐ๊ฒฉ</label>
<input type="text" id="price" name="price" class="form-control"
value="10000" th:value="${item.price}" readonly>
</div> <div>
<label for="quantity">์๋</label>
<input type="text" id="quantity" name="quantity" class="form-control"
value="10" th:value="${item.quantity}" readonly>
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg"
onclick="location.href='editForm.html'"
th:onclick="|location.href='@{/basic/items/{itemId}/ edit(itemId=${item.id})}'|" type="button">์ํ ์์ </button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'"
th:onclick="|location.href='@{/basic/items}'|" type="button">๋ชฉ๋ก์ผ๋ก</button>
</div>
</div>
</div> <!-- /container -->
</body>
</html>
7. ์ํ ๋ฑ๋ก ํผ
BasicItemController์ ์ถ๊ฐ
@GetMapping("/add")
public String addForm() {
return "basic/addForm";
}
๋ทฐ
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css"
th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<style>
.container {
max-width: 560px;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center"> <h2>์ํ ๋ฑ๋ก ํผ</h2>
</div>
<h4 class="mb-3">์ํ ์
๋ ฅ</h4>
<form action="item.html" th:action method="post">
<div>
<label for="itemName">์ํ๋ช
</label>
<input type="text" id="itemName" name="itemName" class="form-
control" placeholder="์ด๋ฆ์ ์
๋ ฅํ์ธ์"> </div>
<div>
<label for="price">๊ฐ๊ฒฉ</label>
<input type="text" id="price" name="price" class="form-control" placeholder="๊ฐ๊ฒฉ์ ์
๋ ฅํ์ธ์">
</div> <div>
<label for="quantity">์๋</label>
<input type="text" id="quantity" name="quantity" class="form-
control" placeholder="์๋์ ์
๋ ฅํ์ธ์"> </div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg" type="submit">์ํ
๋ฑ๋ก</button> </div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'"
</div>
</div>
</form>
th:onclick="|location.href='@{/basic/items}'|" type="button">์ทจ์</button>
</div> <!-- /container -->
</body>
</html>
์ํ ๋ฑ๋ก ์ฒ๋ฆฌ (POST - HTML form)
BasicItemController์ ์ถ๊ฐ
@PostMapping("/add")
public String addItemV1(@RequestParam String itemName,
@RequestParam int price,
@RequestParam Integer quantity,
Model model) {
Item item = new Item();
item.setItemName(itemName);
item.setPrice(price);
item.setQuantity(quantity);
itemRepository.save(item);
model.addAttribute("item", item);
return "basic/item";
}
์ํ ๋ฑ๋ก ์ฒ๋ฆฌ (ModelAttribute)
/**
* @ModelAttribute("item") Item item
* model.addAttribute("item", item); ์๋ ์ถ๊ฐ */
@PostMapping("/add")
public String addItemV2(@ModelAttribute("item") Item item, Model model) {
itemRepository.save(item); //model.addAttribute("item", item); //์๋ ์ถ๊ฐ, ์๋ต ๊ฐ๋ฅ
return "basic/item";
}
* modelattribute ์ด๋ฆ ์๋ต ๊ฐ๋ฅ
8. ์ํ ์์
BasicItemController์ ์ถ๊ฐ
@GetMapping("/{itemId}/edit")
public String editForm(@PathVariable Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "basic/editForm";
}
๋ทฐ
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css"
th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<style>
.container {
max-width: 560px;
} </style>
</head>
<body>
<div class="container">
<div class="py-5 text-center"> <h2>์ํ ์์ ํผ</h2>
</div>
<form action="item.html" th:action method="post">
<div>
<label for="id">์ํ ID</label>
<input type="text" id="id" name="id" class="form-control" value="1"
th:value="${item.id}" readonly>
</div> <div>
<label for="itemName">์ํ๋ช
</label>
<input type="text" id="itemName" name="itemName" class="form-
control" value="์ํA" th:value="${item.itemName}"> </div>
<div>
<label for="price">๊ฐ๊ฒฉ</label>
<input type="text" id="price" name="price" class="form-control"
th:value="${item.price}">
</div> <div>
<label for="quantity">์๋</label>
<input type="text" id="quantity" name="quantity" class="form-
control" th:value="${item.quantity}">
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg" type="submit">์ ์ฅ
</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='item.html'"
th:onclick="|location.href='@{/basic/items/{itemId}(itemId=${item.id})}'|"
</div>
</div>
</form>
type="button">์ทจ์</button>
</div> <!-- /container -->
</body>
</html>
์์ ๋ฐ์
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @ModelAttribute Item item) {
itemRepository.update(itemId, item);
return "redirect:/basic/items/{itemId}";
}
*๋ฆฌ๋ค์ด๋ ํธ : ๋ทฐ ํ ํ๋ฆฟ ํธ์ถํ๋ ๋์ ์ํ ์์ธ ํ๋ฉด์ผ๋ก ์ด๋ํ๋๋ก
9. PRG : POST / REDIRECT / GET
์ฌ๊ฐํ ๋ฌธ์
- ์ํ ๋ฑ๋กํ๊ณ ์น๋ธ๋ผ์ฐ์ ์๋ก๊ณ ์นจ ๋๋ฅด๋ฉด ์ค๋ณต ๋ฑ๋ก๋จ
- ์ํ ๋ฑ๋ก ํ ์ํ ์์ธ ๋ทฐ๋ฅผ ํธ์ถํด์ ๋ณด๋ด๋๋ฐ URL์ ๊ทธ๋๋ก ์ํ ์ ์ฅ URL์ ๋จ์์์
์ ์ฒด ํ๋ฆ
POST ๋ฑ๋ก ํ ์๋ก๊ณ ์นจ
ํด๊ฒฐํ๋๋ฒ? (Post, Redirect Get)
์ํ ์ ์ฅ ํ ๋ทฐ ํ ํ๋ฆฟ์ผ๋ก ์ด๋ํ๋ ๊ฒ์ด ์๋๋ผ ์ํ ์์ธํ๋ฉด์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ ํธ์ถ
์ปจํธ๋กค๋ฌ ์์
/**
* PRG - Post/Redirect/Get
*/
@PostMapping("/add")
public String addItemV5(Item item) {
itemRepository.save(item);
return "redirect:/basic/items/" + item.getId();
}
+item.getId ๋ฐฉ์ ์ํ (URL ์ธ์ฝ๋ฉ ์๋๊ธฐ ๋๋ฌธ์)
RedirectAttributes
- ์ ์ฅ ํ์ธ ๊ธฐ๋ฅ ์ถ๊ฐ
/**
* RedirectAttributes
*/
@PostMapping("/add")
public String addItemV6(Item item, RedirectAttributes redirectAttributes) {
Item savedItem = itemRepository.save(item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/basic/items/{itemId}";
}
redirect:/basic/items/{itemId}
- pathVariable ๋ฐ์ธ๋ฉ: {itemId} - ๋๋จธ์ง๋ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก ์ฒ๋ฆฌ: ?status=true |
'๐จโ๐ป Web Development > Spirng - MVC ํจํด l' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] 6.์คํ๋ง MVC - ๊ธฐ๋ณธ ๊ธฐ๋ฅ (0) | 2023.03.15 |
---|---|
[Spring] 5.์คํ๋ง MVC - ๊ตฌ์กฐ ์ดํด (0) | 2023.03.14 |
[Spring] 4.MVC ํ๋ ์์ํฌ ๋ง๋ค๊ธฐ (0) | 2023.03.13 |
[Spring] 3.์๋ธ๋ฆฟ, JSP, MVC ํจํด (0) | 2023.03.13 |
[Spring] 2.์๋ธ๋ฆฟ (0) | 2023.03.12 |
์ต๊ทผ๋๊ธ