DevLog ๐ถ
[Spring] Thymeleaf๋ฅผ ์ฌ์ฉํด์ ์ํ ๋ฑ๋ก/์์ /์กฐํ ๊ตฌํํ๊ธฐ ๋ณธ๋ฌธ
[Spring] Thymeleaf๋ฅผ ์ฌ์ฉํด์ ์ํ ๋ฑ๋ก/์์ /์กฐํ ๊ตฌํํ๊ธฐ
dolmeng2 2022. 8. 19. 02:04๊น์ํ ๋์ '์คํ๋ง MVC 2ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํ์ฉ ๊ธฐ์ '์ ๋ณด๊ณ ์ ๋ฆฌํ ๊ธ์ ๋๋ค ๐
- ์ง๋ ํฌ์คํ ๊ณผ ์ด์ด์ง๋๋ค :D
| ์ ๋ ฅ ํผ ์ฒ๋ฆฌ
- ์ ๋ฒ ํฌ์คํ ์์ ์งํํ์๋ ์ํ ๋ฑ๋ก ํผ์ ํ์๋ฆฌํ๊ฐ ์ ๊ณตํ๋ ์ ๋ ฅ ํผ ๊ธฐ๋ฅ์ผ๋ก ๋ณ๊ฒฝํด๋ณด์.
- th:object -> ์ปค๋งจ๋ ๊ฐ์ฒด ์ง์
- *{...} -> ์ ํ ๋ณ์ ์, th:object์์ ์ ํํ ๊ฐ์ฒด์ ์ ๊ทผ
- th:field -> HTML ํ๊ทธ์ id, name, value ์์ฑ์ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ค
- ์ฐ์ , th:object๋ฅผ ์ ์ฉํ๊ธฐ ์ํด์ ์ค๋ธ์ ํธ ์ ๋ณด๋ฅผ ๋๊ฒจ์ฃผ์.
[SItemController.java] - ์์
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("item", new SItem());
return "basic/addForm";
}
- ๋ฐ์ดํฐ๊ฐ ๋น์ด์๋ ๋น ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ค์ด์ ๋๊ฒจ์ค๋ค.
[addForm.html] - ์์
<form action="item.html" th:action th:object="${item}" method="post">
<div class="row fw-bold font-monospace">
<div class="col text-center">
<label for="itemName">Name</label>
<input type="text"
th:field="*{itemName}"
class="form-control text-center"
placeholder="Please Enter an Item Name.">
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col text-center">
<label for="price">Price</label>
<input type="text"
th:field="*{price}"
class="form-control text-center"
placeholder="Please Enter an Item Price.">
</div>
<div class="col text-center">
<label for="quantity">Quantity</label>
<input type="text"
th:field="*{quantity}"
class="form-control text-center"
placeholder="Please Enter an Item Quantity.">
</div>
</div>
- th:object="${item}"์ผ๋ก form์์ ์ฌ์ฉํ ๊ฐ์ฒด๋ฅผ ์ง์ ํด์ค๋ค.
: ์ฆ, ๋ชจ๋ธ์์ ๋๊ธด ๋ฐ์ดํฐ์ ํค๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
- th:field="*{itemName}"
: โญ์ฌ์ฉํด์ฃผ๋ฉด ์๋์ผ๋ก id, name, value ๊ฐ์ ๋ฃ์ด์ค๋ค.
-> id="itemName" name="itemName" value=""
- id๋ ๊ณ ์ ํ id ๊ฐ, name์ ์ผ์ข ์ ๋ณ์ ์ด๋ฆ, value๋ ํ๋ฉด์ ํ์๋๋ ๊ฐ์ ์๋ฏธํ๋ค.
- id, name์ ๊ธฐ๋ณธ์ ์ผ๋ก th:field์ ์ ๋ ฅํ ๊ฐ์, value๋ ๋น์์ฃผ๋ ๊ฒ ๊ฐ๋ค.
- ๋ง์ฐฌ๊ฐ์ง๋ก ์์ ํผ์๋ ์ ์ฉํด์ฃผ์.
[editForm.html] - ์์
<form action="item.html" th:action th:object="${item}" method="post">
<div class="row fw-bold font-monospace">
<div class="col text-center">
<label for="id">Id</label>
<input type="text"
th:field="*{id}"
class="form-control text-center"
readonly>
</div>
<div class="col text-center">
<label for="itemName">Name</label>
<input type="text"
th:field="*{itemName}"
class="form-control text-center">
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col text-center">
<label for="price">Price</label>
<input type="text"
th:field="*{price}"
class="form-control text-center">
</div>
<div class="col text-center">
<label for="quantity">Quantity</label>
<input type="text"
th:field="*{quantity}"
class="form-control text-center">
</div>
</div>
- ๋ง์ฐฌ๊ฐ์ง๋ก th:field๋ฅผ ์ ์ฉํด์ฃผ์๋ค. ๊ธฐ์กด์ ์กด์ฌํ๋ id, name, value ๊ฐ์ ์ ๊ฒฝ์จ์ฃผ์ง ์์๋ ๋์ด์ ๋งค์ฐ ํธ๋ฆฌํด์ก๋ค.
<input type="text" id="itemName" name="itemName" value="์ ๋ ฅํ๊ฐ">
- ์์ค๋ฅผ ๋ณด๋ฉด ์ด๋ ๊ฒ ์์์ ์ ๋ง๋ค์ด์ค ๊ฒ์ ๋ณผ ์ ์๋ค. (ํนํ value ์ฒ๋ฆฌ๊ฐ ๊ฐํธํด์ก๋ค)
| ์ฒดํฌ ๋ฐ์ค
- ์ํ ๋ฑ๋ก ์ ์๊ตฌ์ฌํญ์ ์กฐ๊ธ ๋ ์ถ๊ฐํด๋ณด์.
- ํ๋งค ์ฌ๋ถ๋ฅผ ์ฒดํฌ ๋ฐ์ค๋ก ์ ํ, ๋ฑ๋ก ์ง์ญ์ ์ฌ๋ฌ ๊ฐ์ ์ฒดํฌ ๋ฐ์ค ๋ค์ค ์ ํ์ผ๋ก. ์ํ ์ข ๋ฅ๋ฅผ ๋ผ๋์ค ๋ฒํผ, ๋ฐฐ์ก ๋ฐฉ์์ ์ ๋ ํธ ๋ฐ์ค๋ก!
[SItemType.java]
@Getter
@AllArgsConstructor
public enum SItemType {
BOOK("๋์"),
FOOD("์ํ"),
ETC("๊ธฐํ");
private final String description;
}
[DeliveryCode.java]
@Data
@AllArgsConstructor
public class DeliveryCode {
private String code;
private String displayName;
}
- code๋ ์์คํ ๋ด์์ ์ฌ์ฉํ๋ ๊ฐ, displayName์ ๊ณ ๊ฐ์๊ฒ ๋ณด์ฌ์ฃผ๋ ๊ฐ.
[SItem.java] - ์์
@Getter
@NoArgsConstructor
@Setter
public class SItem {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
private Boolean open;
private List<String> regions;
private SItemType itemType;
private String deliveryCode;
public SItem(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
public void changeId(Long id) {
this.id = id;
}
public void changeItemInfo(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
- ์๊ตฌ์ฌํญ์ ๋ฐ๋ฅธ ํ๋งค ์ฌ๋ถ, ์ง์ญ, ์ํ ์ข ๋ฅ, ๋ฐฐ์ก ๋ฐฉ์ ํ๋๋ฅผ ์ถ๊ฐํ์๋ค.
[addForm.html] - ์์
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" id="open" name="open" class="form-check-input">
<label for="open" class="form-check-label">Open</label>
</div>
</div>
</div>
- ๊ฐ๋จํ ์ฒดํฌ๋ฐ์ค๋ฅผ ์์ฑํด์ฃผ์๋ค.
- ์ด๋, ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ํํ๋ฉด HTML form์์๋ open=on์ด๋ผ๋ ๊ฐ์ด ๋์ด๊ฐ๊ณ , ์คํ๋ง์ ์ด๋ฅผ true๋ก ๋ณํํด์ค๋ค.
- ๊ทธ๋์, ์คํ๋ง ๋จ์์์๋ item.open=true๋ผ๋ ๊ฐ์ด ์ฐํ๋ค.
- โญ๊ทธ๋ฌ๋, ์ ํํ์ง ์์ผ๋ฉด ์์ item.open=null๋ก ์ฐํ์ ํ๋ ์์ฒด๊ฐ ์๋ฒ๋ก ์ ์ก๋์ง ์๋๋ค.
- ์ด๋ฌ๋ฉด, ์ฌ์ฉ์๊ฐ ์ฒดํฌ๋ฅผ '์๋์ ์ผ๋ก ํด์ 'ํ์ ๋๋ ์ค์ง ์๊ธฐ ๋๋ฌธ์ ์๋ฒ ๋ด๋ถ์ ๊ฐ ์ ์ฅ์ด ๊ณค๋ํด์ง๋ค.
- ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์, ํ๋์ ํ๋ ํ๋๋ฅผ ๋ง๋ค์ด๋์.
- ์ฒดํฌ๋ฐ์ค ์ด๋ฆ์ _์ ๋ถ์ฌ์ ์ ์กํด์ฃผ๋ฉด ์ฒดํฌ๋ฅผ ํด์ ํ๋ค๊ณ ์ธ์ํ๋ค. ํ๋ ํ๋๋ ํญ์ ์๋ฒ๋ก ์ ์ก๋๋ค!
[addForm.html] - ์์
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" id="open" name="open" class="form-check-input">
<input type="hidden" name="_open" value="on">
<label for="open" class="form-check-label">Open</label>
</div>
</div>
- ์ด๋ฌ๋ฉด, ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ํํ์ ๋๋ open=on&_open=on์ด ํจ๊ป ์ ์ก๋๊ณ , ํด์ ํ์ ๋๋ _open=on๋ง ๊ฐ๊ธฐ ๋๋ฌธ์ ์ฒดํฌ๋์ง ์์๋ค๊ณ ์ธ์ํ ์ ์๋ค!
: ์คํ๋ง์์๋ item.open=true, item.open=false๋ก ์ฑ๊ณต์ ์ผ๋ก ๊ตฌ๋ถํ๋ค!
- ๊ทธ๋ฌ๋, ๊ฐ๋ฐ์๊ฐ ์ง์ ์ถ๊ฐํ๊ธฐ์๋ ์ญ์ ๋ฒ๊ฑฐ๋กญ๋ค. ํ์๋ฆฌํ์์ ์ ๊ณตํ๋๋ ํผ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์.
[addForm.html] - ์์
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" th:field="*{open}" class="form-check-input">
<label for="open" class="form-check-label">Open</label>
</div>
</div>
- th:field="*{open}"์ ์ถ๊ฐํด์ฃผ๋ฉด, ํ์๋ฆฌํ์์ ์๋์ผ๋ก ์๋์ ๊ฐ์ ํ๊ทธ๋ฅผ ์ถ๊ฐํด์ค๋ค.
<input type="checkbox" id="open1" class="form-check-input" name="open" value="true">
<input type="hidden" name="_open" value="on"/>
-> ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, ๊ฐ๋ฐ์๊ฐ ๊ตณ์ด hidden tag๋ฅผ ์ ๊ฒฝ์ฐ์ง ์์๋ ๋๋ค!
์ฐธ๊ณ ๋ก, ์ฒดํฌ๋ฐ์ค๋ ๋ค์ค์ผ๋ก ์ ํ์ด ๋ ์ ์๊ธฐ ๋๋ฌธ์ id๊ฐ open1์ด๋ผ๋ ๊ฐ์ผ๋ก ๋ง๋ค์ด์ง๋ค (์๋์ผ๋ก 1์ ์ถ๊ฐํด์ค)
์ด์ ๋ํด์๋ ๋ค์์ ํ ๋ฒ ๋ ๋ค๋ฃฐ ์์ !
[item.html] - ์์
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" id="open" th:field="${item.open}"
class="form-check-input" disabled>
<label for="open" class="form-check-label">Open</label>
</div>
</div>
</div>
- ์ฌ๊ธฐ์๋ th:object ์ ์ธ์ ์ ํด์คฌ์ผ๋๊น th.field="*{item.open}"์ผ๋ก ์จ์ผ ํ๋ค!
- ๋ํ, ์ฒดํฌ๊ฐ ๋์ด ์์ ๊ฒฝ์ฐ ๊ธฐ์กด์๋ checked="checked" ๋ฅผ ๊ฐ๋ฐ์๊ฐ ์ฒ๋ฆฌํ์ด์ผ ํ๋๋ฐ, ์ด ์ญ์ ํ์๋ฆฌํ๊ฐ ์๋์ผ๋ก ํด์ค๋ค.
- ์๋๋ ํ์๋ฆฌํ๊ฐ ์๋์ผ๋ก ์์ฑํด์ค ์์ฑ์ด๋ค.
<input type="checkbox" id="open" class="form-check-input" disabled name="open" value="true" checked="checked">
- ํ์๋ฆฌํ๋ th:field ๊ฐ๊ณผ th:value ๊ฐ์ ๋น๊ตํด์ ์๋์ผ๋ก ์ถ๊ฐํด์ค๋ค.
[editForm.html] - ์์
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" id="open" th:field="*{open}" class="form-check-input">
<label for="open" class="form-check-label">Open</label>
</div>
</div>
</div>
[SItem.java] - ์์
public void changeItemInfo(String itemName, Integer price, Integer quantity,
Boolean open, List<String> regions, SItemType itemType,
String deliveryCode) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
this.open = open;
this.regions = regions;
this.itemType = itemType;
this.deliveryCode = deliveryCode;
}
[SItemRepository.java] - ์์
public void update(Long itemId, SItem updateInfo) {
SItem findItem = store.get(itemId);
findItem.changeItemInfo(updateInfo.getItemName(), updateInfo.getPrice(), updateInfo.getQuantity(),
updateInfo.getOpen(), updateInfo.getRegions(), updateInfo.getItemType(), updateInfo.getDeliveryCode());
}
| ์ฒดํฌ ๋ฐ์ค - ์ฌ๋ฌ ๊ฐ
- ์ฒดํฌ ๋ฐ์ค๋ฅผ ์ฌ๋ฌ ๊ฐ ์ฒดํฌํ ์ ์๋๋ก ๋ง๋ค์ด๋ณด์! (๋ฑ๋ก ์ง์ญ)
[SItemController.java] - ์ถ๊ฐ
@ModelAttribute("regions")
public Map<String, String> regions() {
Map<String, String> regions = new LinkedHashMap<>();
regions.put("SEOUL", "์์ธ");
regions.put("BUSAN", "๋ถ์ฐ");
regions.put("JEJU", "์ ์ฃผ");
return regions;
}
- @ModelAttribute๋ฅผ ๋ฉ์๋ ๋จ์์ ์ด๋ค๊ณ ...?! ์ถ์ ์๋ ์๋ค.
- ๋ฑ๋ก ํผ, ์์ธ ํ๋ฉด, ์์ ํผ์์๋ ๋ชจ๋ ์ง์ญ์ด ์ฐ์ธ ์ฒดํฌ ๋ฐ์ค๋ฅผ ๋ฐ๋ณตํด์ ๋ณด์ฌ์ค์ผ ํ๋๋ฐ, ๊ฐ ์ปจํธ๋กค๋ฌ์์ model.addAttribute๋ฅผ ์ฌ์ฉํด์ ์ถ๊ฐํด์ฃผ๊ธฐ์๋ ๋๋ฌด ๋ฒ๊ฑฐ๋กญ๋ค.
- ๊ทธ๋ ๊ธฐ ๋๋ฌธ์, ๋ฉ์๋ ๋จ์์ ์ฌ์ฉํ์ฌ ํด๋น ์ปจํธ๋กค๋ฌ์ ์์ฒญ ์ regions์์ ๋ฐํ๋ ๊ฐ์ด ์๋์ผ๋ก model์ ๋ด๊ธฐ๋๋ก ํด์ฃผ์!
[addForm.html] - ์ถ๊ฐ
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Regions</div>
<div th:each="region : ${regions}"
class="form-check form-check-inline">
<input type="checkbox" th:field="*{regions}"
th:value="${region.key}" class="form-check-input">
<label th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>Seoul</label>
</div>
</div>
</div>
- th:each๋ฅผ ํตํด ๋ฐ๋ณต๋ฌธ์ผ๋ก ์ฒดํฌ๋ฐ์ค๋ฅผ ์์ฑํด์ฃผ์๋ค.
<input type="checkbox" th:field="*{regions}" th:value="${region.key}" class="form-check-input">
- regions๋ฅผ ์ฌ์ฉํ๋ฉฐ, value ๊ฐ์ผ๋ก key๋ฅผ ๋ฃ์๋ค (์ฆ, ๊ฐ region ์ด๋ฆ์ ์์ด ์ด๋ฆ)
- ๊ทธ๋ฆฌ๊ณ , ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ง ๋๋ value ๊ฐ, ์ฆ region์ ํ๊ธ ์ด๋ฆ์ด ๋ณด์ฌ์ง๋๋ก ํ์๋ค.
<label th:for="${#ids.prev('regions')}" th:text="${region.value}" class="form-check-label">
- โญ๋ณดํต label์ for๋ input์์ ์ฐ์ธ id์ ๋์ผํ ๊ฐ์ ๋ฃ๋๋ค. (input๊ณผ label์ ์ฐ๊ด์ํค๊ธฐ ์ํด์)
- ์ด๋, th:for์ ๋ํด ids.prev๋ผ๋ ๊ฑธ ์ค์ ํ๋๋ฐ, ์ด๋ ๋ฐ๋ณต๋ฌธ์ผ๋ก ์ฒดํฌ๋ฐ์ค ์์ฑ ์ id๊ฐ ๋ชจ๋ regions๋ก ๋์ผํด์ง ์ ์๊ธฐ ๋๋ฌธ์,
๊ณ ์ ํ id๋ฅผ ๊ฐ์ง๊ฒ ํ๊ธฐ ์ํด์ ์์๋ก 1, 2, 3 ์ซ์๊ฐ ๋ถ๋๋ก ๋ง๋ค์ด์ฃผ์๋ค. (name์ ๊ฒฝ์ฐ ๋์ผํด๋ ๋ฌด๊ดํจ)
- ์ค์ ๋ก, ์์ฑ๋ ๊ฑธ ๋ณด๋ฉด
<input type="checkbox" value="SEOUL" class="form-check-input" id="regions1" name="regions"><input type="hidden" name="_regions" value="on"/>
<label for="regions1"class="form-check-label">์์ธ</label>
<input type="checkbox" value="BUSAN" class="form-check-input" id="regions2" name="regions"><input type="hidden" name="_regions" value="on"/>
<label for="regions2" class="form-check-label">๋ถ์ฐ</label>
- ์ด๋ฐ ์์ผ๋ก id ๊ฐ์ด ์ฆ๊ฐ๋๋ฉด์ ์๊ธฐ๋ ๊ฑธ ๋ณผ ์ ์๋ค!
- ์ฐธ๊ณ ๋ก, ๊ตณ์ด ์ ๋ ๊ฒ ์ฐ์ง ์๊ณ th:for="${regions}"๋ผ๊ณ ํด๋ ์๋์ผ๋ก id๊ฐ ์ฆ๊ฐํ๋ฉด์ ์๊ธฐ๊ธฐ๋ ํ๋ค... :D
๐ฉ prev ์ธ์ ๋ค์ํ ์กฐ๊ฑด
- prev์ ๊ฒฝ์ฐ ์ด์ ์ํ์ค์ ๊ฐ์ + 1
- region1, region2, region3...
- next์ ๊ฒฝ์ฐ ๋ค์ ์ํ์ค์ ๊ฐ์ + 1
- region2, region3, region4...
- seq๋ ํ์ฌ ์ํ์ค ๊ฐ์ ๋ฐํ ํ ์ํ์ค ๊ฐ์ +1
- region2, region4, region6...
๐ฉ ids์ ๊ฒฝ์ฐ ๋ณดํต label ํ๊ทธ์์ ์ฌ์ฉํ๋๋ฐ, label์ด form์ ์์ ์์นํ๋ค๋ฉด next๋ฅผ, ์ฐ๋ฆฌ์ ์์ ์ฒ๋ผ form์ ๋ค์ ์จ๋ค๋ฉด prev๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค๊ณ ํ๋ค. ๊ทธ๋ฌ๋, seq์ ๊ฒฝ์ฐ ์กฐ๊ธ ๋ค๋ฅด๊ฒ ๋์ํ๋ค.
- label์ด ๋จผ์ ์ค๋ ๊ฒฝ์ฐ ํ์ฌ ์ํ์ค ๊ฐ์ ๋ฐํํ ๋ค +1์ ์ํํ๋ค.
- label์ด ๋์ค์ ์ค๋ ๊ฒฝ์ฐ ํ์ฌ ์ํ์ค ๊ฐ์์ +1์ ํ ๋ค ๋ฐํ์ ํด์ค๋ค.
โ ์ด์ ๊ด๋ จํด์ ๋ค๋ฅธ ๋ถ์ด ํ ์คํธ๋ฅผ ํด์ฃผ์ จ๋ค๊ณ ํ์ ์, ๋์ถฉ ์ฎ๊ฒจ๋ณด์๋ฉด...
- th:each๋ iteration์ด ๊ฐ๋ฅํ๋ค๋ฉด ๋ฐ๋ณต์ ํ์ง๋ง, index๋ฅผ ์ ๊ณตํด์ฃผ์ง๋ ์๋๋ค.
- ๊ทธ๋์, ๊ฐ์ฒด ์ด์ฉ ์ ๊ฐ์์ index๋ฅผ ์์ฑํ๋ค. (์ด๋ฆ์ ID Count) ์ด๋ 1๋ถํฐ ์์ํ๋ค.
- ์ด๋, ๊ฐ์ฒด๋ฅผ ์ด์ฉํ์ง ์์ผ๋ฉด index๋ฅผ ์์ฑํ์ง ์๊ณ , ์ด์ฉ์ ํ ๋ ์์ฑํ๋ค.
- ๋ฃจํ๋ฅผ ๋ ๋๋ง๋ค 1์ฉ ์ฆ๊ฐํ๋ค.
- #ids.prev์ ๊ฒฝ์ฐ ์ด์ ์ ์ด์ฉํ์๋ ๊ฐ์์ index๊ฐ ์๋์ง ํ์ธํ๊ณ , ๊ทธ ๊ฐ์ ๊ฐ์ ธ์จ๋ค.
-- ๋ง์ฝ label์ด ๋จผ์ ์ค๋๋ฐ ids.prev๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ๊ฐ์์ index๋ฅผ ์ฌ์ฉํ ์ ์ด ์์ผ๋๊น!
- #ids.next์ ๊ฒฝ์ฐ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ์์ฑ๋ ๊ฐ์์ ์ธ๋ฑ์ค ๊ฐ์ ๊ฐ์ ธ์จ๋ค.
-- ์ด๋, ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์๋ ์ธ๋ฑ์ค๊ฐ ์์ฑ๋์ง ์์์ ํ ๋ฐ, #ids.next๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด ์ฌ์ฉ์ด ์ ๋์ด๋ ๋ฏธ๋ฆฌ ์ด์ฉ ๊ฐ๋ฅํ๋ค.
- #ids.seq์ ๊ฒฝ์ฐ, ๊ฐ์์ index๋ฅผ ๋ฏธ๋ฆฌ ์ด์ฉํด๋๊ณ (ids.next์ฒ๋ผ) 1์ ์ฆ๊ฐํด๋๋ค(i++). ๊ทธ๋์ 2์ฉ ์ฆ๊ฐํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๋ ๊ฒ.
์ฐธ๊ณ ) https://inflearn.com/questions/273026
- ์๋ฌดํผ, ๋ง์ฝ ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ ๋ณด๊ฐ ์ ์ก๋๋ค.
regions=SEOUL&_regions=on®ions=BUSAN&_regions=on&_regions=on
ํ๋ ํ๊ทธ์ ์ ๋ณด๊ฐ ์ ์ก๋๋ค๋ ์ !
- ์๋ฌด๊ฒ๋ ์ ํ ์ ํ๋ฉด ์ด๋ ๊ฒ ๋ฌ๋ค.
_regions=on&_regions=on&_regions=on
[item.html] - ์ถ๊ฐ
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Regions</div>
<div th:each="region : ${regions}"
class="form-check form-check-inline">
<input type="checkbox" th:field="${item.regions}"
th:value="${region.key}" class="form-check-input" disabled>
<label th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>Seoul</label>
</div>
</div>
</div>
- ๋ง์ฐฌ๊ฐ์ง๋ก ์ ํํ ์ฒดํฌ๋ฐ์ค์ ๋ํด์๋ ์กฐํ ์์ checked="checked" ์ต์ ์ด ์๋์ผ๋ก ์ถ๊ฐ๋์ด ์๋ค!
[editForm.html]
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Regions</div>
<div th:each="region : ${regions}"
class="form-check form-check-inline">
<input type="checkbox" th:field="*{regions}"
th:value="${region.key}" class="form-check-input">
<label th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>Seoul</label>
</div>
</div>
</div>
| ๋ผ๋์ค ๋ฒํผ
- ์ด๋ฒ์๋ ์ํ ์ข ๋ฅ ์ง์ ์ ์ํ ๋ผ๋์ค ๋ฒํผ์ ์ถ๊ฐํด์ฃผ์.
[SItemController.java] - ์ถ๊ฐ
@ModelAttribute("itemTypes")
public SItemType[] itemTypes() {
return SItemType.values();
}
- ์๊น์ ๋์ผํ ์๋ฆฌ๋ก @ModelAttribute๋ฅผ ํ์ฉํด์ ๋ชจ๋ธ์ ๋ฃ์ด์ฃผ์.
- enum์ values๋ฅผ ํ์ฉํ๋ฉด enum์ ๋ชจ๋ ์ ๋ณด๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํ๋ฐ์ ์ ์๋ค.
-> [BOOK, FOOD, ETC]
[addForm.html]
<div class="col">
<div>Item Type</div>
<div th:each="type: ${itemTypes}"
class="form-check form-check-inline">
<input type="radio" th:field="*{itemType}"
th:value="${type.name()}"
class="form-check-input">
<label th:for="${#ids.prev('itemType')}"
th:text="${type.description}"
class="form-check-label">
BOOK
</label>
</div>
</div>
- ๋ผ๋์ค ๋ฒํผ์ ํ ๋ฒ ์ ํ๋๋ฉด ํญ์ ๋ค๋ฅธ ๊ฑธ ๋ ์ ํํด์ผ ํ๊ธฐ ๋๋ฌธ์ ํ๋ ํ๋๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์๋ค!
- type.name์ ํ๋ฉด enum ํ์ ์ name ๋ถ๋ถ์ ๊ฐ์ ธ์ค๊ฒ ๋๋ค.
ex) BOOK("๋์")๋ผ๊ณ ํ์ ๋ name์ BOOK์ด ๋๋ ๊ฒ.
[item.html]
<div class="col">
<div>Item Type</div>
<div th:each="type: ${itemTypes}"
class="form-check form-check-inline">
<input type="radio" th:field="${item.itemType}"
th:value="${type.name()}"
class="form-check-input" disabled>
<label th:for="${#ids.prev('itemType')}"
th:text="${type.description}"
class="form-check-label">
BOOK
</label>
</div>
</div>
[editForm.html]
<div class="col">
<div>Item Type</div>
<div th:each="type: ${itemTypes}"
class="form-check form-check-inline">
<input type="radio" th:field="*{itemType}"
th:value="${type.name()}"
class="form-check-input">
<label th:for="${#ids.prev('itemType')}"
th:text="${type.description}"
class="form-check-label">
BOOK
</label>
</div>
</div>
- ๋ง์ฐฌ๊ฐ์ง๋ก ์ ํ๋ ๊ฒ์ ๋ํด์๋ ํ์๋ฆฌํ๊ฐ ์๋์ผ๋ก checked="checked" ์ต์ ์ ๋ฃ์ด์ค๋ค.
- ์ถ๊ฐ์ ์ผ๋ก, ํ์๋ฆฌํ์์๋ ENUM ํ์ ์ ์ง์ ์ ๊ทผ๋ ๊ฐ๋ฅํ๋ค.
<div th:each="type : ${T(ํจํค์ง๊ฒฝ๋ก.SItemType).values()}">
- ์ด๋ฐ ์์ผ๋ก ์ง์ ์ ๊ทผ์ ๋์ง๋ง, ํจํค์ง ๊ฒฝ๋ก๊ฐ ๋ฐ๋๋ฉด ์ฌ๊ธฐ๋ ๋ฐ๊ฟ์ค์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฌ๋งํ๋ฉด ๋น์ถ์ฒํ๋ค.
| ์ ๋ ํธ ๋ฐ์ค
- ์ฌ๋ฌ ์ ํ์ง ์ค์ ํ๋๋ฅผ ์ ํํ ์ ์๋ค. ๋ฐฐ์ก ๋ฐฉ์์ ์ด๊ฑธ๋ก ๊ตฌํํด๋ณด์.
[SItemController.java] - ์ถ๊ฐ
@ModelAttribute("deliveryCodes")
public List<DeliveryCode> deliveryCodes() {
return CreateDeliveryCode.getCodes();
}
@NoArgsConstructor
static class CreateDeliveryCode {
private static final List<DeliveryCode> deliveryCodes =
Arrays.asList(new DeliveryCode("FAST", "๋น ๋ฅธ ๋ฐฐ์ก"),
new DeliveryCode("NORMAL", "์ผ๋ฐ ๋ฐฐ์ก"),
new DeliveryCode("SLOW", "๋๋ฆฐ ๋ฐฐ์ก"));
public static List<DeliveryCode> getCodes() {
return deliveryCodes;
}
}
- ์ด๋ฒ์๋ ์๋ฐ ๊ฐ์ฒด ๋ฆฌ์คํธ๋ฅผ ๋ฐํํ์๋ค.
- ๋ฉ์๋ ๋ด์์ ๋ฆฌ์คํธ๋ฅผ ์ ์ธํ๊ณ add๋ฅผ ํด์ค๋ ๋ฌด๋ฐฉํ๋ค.
๊ทธ๋ฌ๋, deliveryCodes()๊ฐ ์ปจํธ๋กค๋ฌ๊ฐ ํธ์ถ๋ ๋๋ง๋ค ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๊ฐ ์ผ์ด๋๊ธฐ ๋๋ฌธ์ ํด๋์ค๋ฅผ ๋ณ๋๋ก ์ ์ธํ๊ณ ๋ฏธ๋ฆฌ deliveryCodes์ ๋ํด ์ด๊ธฐํ๋ฅผ ์งํํด๋ ๋ฆฌ์คํธ๋ฅผ ๋ฆฌํดํ๋๋ก ๋ง๋ค์๋ค.
์ถ๊ฐ์ ์ผ๋ก, static final๋ก ํด์ ์ฑ๊ธํค์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์๋๋ก ํ์๋ค.
[addForm.html] - ์ถ๊ฐ
<div class="col">
<div>Delivery</div>
<select th:field="*{deliveryCode}" class="form-select">
<option value="">== SELECT DELIVERY TYPE ==</option>
<option th:each="deliveryCode : ${deliveryCodes}"
th:value="${deliveryCode.code}"
th:text="${deliveryCode.displayName}">FAST</option>
</select>
</div>
- th:each๋ฌธ์ ํตํด value์ ๊ฐ๊ฐ์ code ๊ฐ์ด ๋ค์ด๊ฐ๋๋ก ํ๊ณ , ์ฌ์ฉ์์๊ฒ๋ text ๊ฐ์ด ๋ณด์ฌ์ง๋๋ก ํ์๋ค.
- ๋ธ๋ผ์ฐ์ ์์๋ ๋ค์๊ณผ ๊ฐ์ด ๋์จ๋ค.
<select class="form-select" id="deliveryCode" name="deliveryCode">
<option value="">== SELECT DELIVERY TYPE ==</option>
<option value="FAST">๋น ๋ฅธ ๋ฐฐ์ก</option>
<option value="NORMAL">์ผ๋ฐ ๋ฐฐ์ก</option>
<option value="SLOW">๋๋ฆฐ ๋ฐฐ์ก</option>
</select>
- ์ฐธ๊ณ ๋ก, ์ ๋ ํธ ๋ฐ์ค์์๋ ์๋ฌด๊ฒ๋ ์ ํํ์ง ์์ผ๋ฉด ๋น ๊ฐ์ด ์ ๋ฌ๋๋ค.
[item.html]
<div class="col">
<div>Delivery</div>
<select th:field="${item.deliveryCode}" class="form-select" disabled>
<option value="">== SELECT DELIVERY TYPE ==</option>
<option th:each="deliveryCode : ${deliveryCodes}"
th:value="${deliveryCode.code}"
th:text="${deliveryCode.displayName}">FAST</option>
</select>
</div>
[editForm.html]
<div class="col">
<div>Delivery</div>
<select th:field="*{deliveryCode}" class="form-select">
<option value="">== SELECT DELIVERY TYPE ==</option>
<option th:each="deliveryCode : ${deliveryCodes}"
th:value="${deliveryCode.code}"
th:text="${deliveryCode.displayName}">FAST</option>
</select>
</div>
- ๋ง์ฐฌ๊ฐ์ง๋ก ์ ํ๋ ๊ฐ์ ๋ํด์๋ ์๋์ผ๋ก checked="checked" ์ต์ ์ ๋ฃ์ด์ค๋ค.
| ์ฌ์ฉํ ์ต์ข ์ฝ๋
[Items]
[saveForm]
[Item]
[edit]
โ Code
[ํจํค์ง ๊ตฌ์กฐ]
- hello-form์ ์ด์ ํ๋ก์ ํธ์์ ๋ง๋ ๊ฑฐ์ฌ์ ๋ฌด์ํด๋ ๋๋ค...!
[SItem.java]
@Getter
@NoArgsConstructor
@Setter
public class SItem {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
private Boolean open;
private List<String> regions;
private SItemType itemType;
private String deliveryCode;
public SItem(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
public void changeId(Long id) {
this.id = id;
}
public void changeItemInfo(String itemName, Integer price, Integer quantity,
Boolean open, List<String> regions, SItemType itemType,
String deliveryCode) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
this.open = open;
this.regions = regions;
this.itemType = itemType;
this.deliveryCode = deliveryCode;
}
}
[DeliveryCode.java]
@Data
@AllArgsConstructor
public class DeliveryCode {
private String code;
private String displayName;
}
[SItemType.java]
@Getter
@AllArgsConstructor
public enum SItemType {
BOOK("๋์"),
FOOD("์ํ"),
ETC("๊ธฐํ");
private final String description;
}
[SItemRepository.java]
@Repository
public class SItemRepository {
private static final Map<Long, SItem> store = new ConcurrentHashMap<>();
private static AtomicLong sequence = new AtomicLong(0);
public SItem save(SItem item) {
item.changeId(sequence.incrementAndGet());
store.put(item.getId(), item);
return item;
}
public SItem findById(Long id) {
return store.get(id);
}
public List<SItem> findAll() {
return new ArrayList<>(store.values());
}
public void update(Long itemId, SItem updateInfo) {
SItem findItem = store.get(itemId);
findItem.changeItemInfo(updateInfo.getItemName(), updateInfo.getPrice(), updateInfo.getQuantity(),
updateInfo.getOpen(), updateInfo.getRegions(), updateInfo.getItemType(), updateInfo.getDeliveryCode());
}
public void clearStore() {
store.clear();
}
}
[SItemController.java]
@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class SItemController {
private final SItemRepository repository;
@GetMapping
public String items(Model model) {
List<SItem> items = repository.findAll();
model.addAttribute("items", items);
return "basic/items";
}
@GetMapping("/{itemId}")
public String item(@PathVariable Long itemId, Model model) {
SItem item = repository.findById(itemId);
model.addAttribute("item", item);
return "basic/item";
}
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("item", new SItem());
return "basic/addForm";
}
@PostMapping("/add")
public String addItemV2 (SItem item, Model model, RedirectAttributes redirectAttributes) {
SItem savedItem = repository.save(item);
model.addAttribute("item", item);
redirectAttributes.addAttribute("itemId", savedItem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/basic/items/{itemId}";
}
@GetMapping("/{itemId}/edit")
public String editForm(@PathVariable Long itemId, Model model) {
SItem item = repository.findById(itemId);
model.addAttribute("item", item);
return "basic/editForm";
}
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, SItem item, Model model) {
repository.update(itemId, item);
model.addAttribute("item", item);
return "redirect:/basic/items/{itemId}";
}
@ModelAttribute("regions")
public Map<String, String> regions() {
Map<String, String> regions = new LinkedHashMap<>();
regions.put("SEOUL", "์์ธ");
regions.put("BUSAN", "๋ถ์ฐ");
regions.put("JEJU", "์ ์ฃผ");
return regions;
}
@ModelAttribute("itemTypes")
public SItemType[] itemTypes() {
return SItemType.values();
}
@ModelAttribute("deliveryCodes")
public List<DeliveryCode> deliveryCodes() {
return CreateDeliveryCode.getCodes();
}
@NoArgsConstructor
static class CreateDeliveryCode {
private static final List<DeliveryCode> deliveryCodes
= Arrays.asList(new DeliveryCode("FAST", "๋น ๋ฅธ ๋ฐฐ์ก"),
new DeliveryCode("NORMAL", "์ผ๋ฐ ๋ฐฐ์ก"),
new DeliveryCode("SLOW", "๋๋ฆฐ ๋ฐฐ์ก"));
public static List<DeliveryCode> getCodes() {
return deliveryCodes;
}
}
// ํ
์คํธ ๋ฐ์ดํฐ ์ถ๊ฐ (์์กด๊ด๊ณ ์ฃผ์
์ดํ ์คํ)
@PostConstruct
public void init() {
repository.save(new SItem("itemA", 10000, 10));
repository.save(new SItem("itemB", 20000, 20));
}
}
-----------------
[addform.html]
<!DOCTYPE html>
<html lang="en" 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">
<title>Item Save Form</title>
<style>
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2 class="font-monospace fw-bold">Item Save Form</h2>
</div>
<form action="item.html" th:action th:object="${item}" method="post">
<div class="row fw-bold font-monospace">
<div class="col text-center">
<label for="itemName">Name</label>
<input type="text"
th:field="*{itemName}"
class="form-control text-center"
placeholder="Please Enter an Item Name.">
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col text-center">
<label for="price">Price</label>
<input type="text"
th:field="*{price}"
class="form-control text-center"
placeholder="Please Enter an Item Price.">
</div>
<div class="col text-center">
<label for="quantity">Quantity</label>
<input type="text"
th:field="*{quantity}"
class="form-control text-center"
placeholder="Please Enter an Item Quantity.">
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" th:field="*{open}" class="form-check-input">
<label for="open" class="form-check-label">Open</label>
</div>
</div>
<div class="col">
<div>Delivery</div>
<select th:field="*{deliveryCode}" class="form-select">
<option value="">== SELECT DELIVERY TYPE ==</option>
<option th:each="deliveryCode : ${deliveryCodes}"
th:value="${deliveryCode.code}"
th:text="${deliveryCode.displayName}">FAST</option>
</select>
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Regions</div>
<div th:each="region : ${regions}"
class="form-check form-check-inline">
<input type="checkbox" th:field="*{regions}"
th:value="${region.key}" class="form-check-input">
<label th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>Seoul</label>
</div>
</div>
<div class="col">
<div>Item Type</div>
<div th:each="type: ${itemTypes}"
class="form-check form-check-inline">
<input type="radio" th:field="*{itemType}"
th:value="${type.name()}"
class="form-check-input">
<label th:for="${#ids.prev('itemType')}"
th:text="${type.description}"
class="form-check-label">
BOOK
</label>
</div>
</div>
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-warning btn-lg"
type="submit">
โญ
</button>
</div>
<div class="col">
<button class="w-100 btn btn-danger btn-lg"
onclick="location.href='items.html'"
th:onclick="|location.href='@{/basic/items}'|"
type="button">
โ
</button>
</div>
</div>
</form>
</div>
</body>
</html>
[editForm.html]
<!DOCTYPE html>
<html lang="en" 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">
<title>Item Edit Form</title>
<style>
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2 class="font-monospace fw-bold">Item Edit Form</h2>
</div>
<form action="item.html" th:action th:object="${item}" method="post">
<div class="row fw-bold font-monospace">
<div class="col text-center">
<label for="id">Id</label>
<input type="text"
th:field="*{id}"
class="form-control text-center"
readonly>
</div>
<div class="col text-center">
<label for="itemName">Name</label>
<input type="text"
th:field="*{itemName}"
class="form-control text-center">
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col text-center">
<label for="price">Price</label>
<input type="text"
th:field="*{price}"
class="form-control text-center">
</div>
<div class="col text-center">
<label for="quantity">Quantity</label>
<input type="text"
th:field="*{quantity}"
class="form-control text-center">
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" id="open" th:field="*{open}" class="form-check-input">
<label for="open" class="form-check-label">Open</label>
</div>
</div>
<div class="col">
<div>Delivery</div>
<select th:field="*{deliveryCode}" class="form-select">
<option value="">== SELECT DELIVERY TYPE ==</option>
<option th:each="deliveryCode : ${deliveryCodes}"
th:value="${deliveryCode.code}"
th:text="${deliveryCode.displayName}">FAST</option>
</select>
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Regions</div>
<div th:each="region : ${regions}"
class="form-check form-check-inline">
<input type="checkbox" th:field="*{regions}"
th:value="${region.key}" class="form-check-input">
<label th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>Seoul</label>
</div>
</div>
<div class="col">
<div>Item Type</div>
<div th:each="type: ${itemTypes}"
class="form-check form-check-inline">
<input type="radio" th:field="*{itemType}"
th:value="${type.name()}"
class="form-check-input">
<label th:for="${#ids.prev('itemType')}"
th:text="${type.description}"
class="form-check-label">
BOOK
</label>
</div>
</div>
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-warning btn-lg"
type="submit">
โญ
</button>
</div>
<div class="col">
<button class="w-100 btn btn-danger btn-lg"
onclick="location.href='items.html'"
th:onclick="|location.href='@{/basic/items/{itemId}(itemId=${item.id})}'|"
type="button">
โ
</button>
</div>
</div>
</form>
</div>
</body>
</html>
[item.html]
<!DOCTYPE html>
<html lang="en" 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">
<title>item Detail</title>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2 class="font-monospace fw-bold">Item Detail</h2>
</div>
<h2 class="font-monospace fw-bold text-center text-danger"
th:if="${param.status}" th:text="'Save Success!'"></h2>
<div class="row fw-bold font-monospace">
<div class="col text-center">
<label for="itemId">ID</label>
<input type="text" id="itemId" name="itemId"
class="form-control text-center"
value="1" th:value="${item.id}" readonly>
</div>
<div class="col text-center">
<label for="itemName">Name</label>
<input type="text" id="itemName" name="itemName"
class="form-control text-center"
value="์ํA" th:value="${item.itemName}" readonly>
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col text-center">
<label for="price">Price</label>
<input type="text" id="price" name="price"
class="form-control text-center"
value="10000" th:value="${item.price}" readonly>
</div>
<div class="col text-center">
<label for="quantity">Quantity</label>
<input type="text" id="quantity" name="quantity"
class="form-control text-center"
value="10" th:value="${item.quantity}" readonly>
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Sales status</div>
<div class="form-check">
<input type="checkbox" id="open" th:field="${item.open}"
class="form-check-input" disabled>
<label for="open" class="form-check-label">Open</label>
</div>
</div>
<div class="col">
<div>Delivery</div>
<select th:field="${item.deliveryCode}" class="form-select" disabled>
<option value="">== SELECT DELIVERY TYPE ==</option>
<option th:each="deliveryCode : ${deliveryCodes}"
th:value="${deliveryCode.code}"
th:text="${deliveryCode.displayName}">FAST</option>
</select>
</div>
</div>
<div class="row mt-2 fw-bold font-monospace">
<div class="col">
<div>Regions</div>
<div th:each="region : ${regions}"
class="form-check form-check-inline">
<input type="checkbox" th:field="${item.regions}"
th:value="${region.key}" class="form-check-input" disabled>
<label th:for="${#ids.prev('regions')}"
th:text="${region.value}"
class="form-check-label"
>Seoul</label>
</div>
</div>
<div class="col">
<div>Item Type</div>
<div th:each="type: ${itemTypes}"
class="form-check form-check-inline">
<input type="radio" th:field="${item.itemType}"
th:value="${type.name()}"
class="form-check-input" disabled>
<label th:for="${#ids.prev('itemType')}"
th:text="${type.description}"
class="form-check-label">
BOOK
</label>
</div>
</div>
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-warning 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-info btn-lg"
onclick="location.href='items.html'"
th:onclick="|location.href='@{/basic/items}'|"
type="button">
๐
</button>
</div>
</div>
</div>
</body>
</html>
[items.html]
<!DOCTYPE html>
<html lang="en" 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">
<title>item List</title>
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2 class="font-monospace fw-bold">Item List</h2>
<button class="btn btn-warning float-end text-white"
onclick="location.href='addForm.html'"
th:onclick="|location.href='@{/basic/items/add}'|"
type="button">
โ
</button>
</div>
<div class="mt-4 font-monospace">
<table class="table table-hover table-bordered">
<thead>
<tr class="text-center">
<th>ID</th>
<th>์ํ๋ช
</th>
<th>๊ฐ๊ฒฉ</th>
<th>์๋</th>
</tr>
</thead>
<tbody class="text-center">
<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}">ItemName</a></td>
<td th:text="${item.price}">Price</td>
<td th:text="${item.quantity}">Quantity</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
- ํ์๋ฆฌํ์ ๋ํด ์ ๋๋ก ๊ณต๋ถํ๋ ์๊ฐ์ด์๋ค...! ๋ค์ ํฌ์คํ ๋ถํฐ๋ ๋ฉ์์ง, ๊ตญ์ ํ ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ณด์.