th:object
: 커멘드 객체를 지정한다
*{...}
: 선택변수식아라 하며 th:object
에서 선택한 객체에 접근한다.
th:field
: HTML 태그의 id
, name
, value
속성을 자동으로 처리해준다.
등록폼 처리
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("item", new Item());
return "form/addForm";
}
<form action="item.html" th:action th:object="${item}" method="post">
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" th:field="*{itemName}"
class="form- control" placeholder="이름을 입력하세요">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" th:field="*{price}"
class="form-control" placeholder="가격을 입력하세요">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" th:field="*{quantity}"
class="form- control" placeholder="수량을 입력하세요">
</div>
th:object="${item}"
: <form>
에서 사용할 객체를 지정한다. 선택 변수 식( *{...}
)을 적용할 수 있다.
th:field="*{itemName}"
th:field="*{itemName}"
는 id
,name
,value
속성을 모두 자동으로 만들어준다.id
:th:field
에서 지정한 변수 이름과 같다.name
: th:field
에서 지정한 변수 이름과 같다.value
: th:field
에서 지정한 변수의 값을 사용한다.<div>판매 여부</div>
<div>
<div class="form-check">
<input type="checkbox" id="open" name="open" class="form-check-input">
<label for="open" class="form-check-label">판매 오픈</label>
</div>
</div>
폼에 해당 HTML 태그를 추가 해 이 데이터가 전달되는 상황이다.
@PostMapping("/add")
public String addItem(Item item, RedirectAttributes redirectAttributes) {
log.info("item.open={}", item.getOpen());
...
}
컨트롤러로 해당 폼을 전달받은 후 log를 찍어보면 체크박스를 선택하면 true , 선택하지 않으면 null값이 전달된다.
<input type="hidden" name="_open" value="on"/>
체크 박스 이름 앞에 언더스코어를 붙여서 전송하면 체크를 해제했다고 인식할 수 있다.
체크를 해제한 경우 여기에서 open
은 전송되지 않고, _open
만 전송되는데 이 경우 스프링 mvc는 체크를 해제했다고 판단한다.
하지만 개발할 때 마다 이렇게 히든 필드를 추가하는 것은 매우 귀찮다. 타임리프가 제공하는 폼 기능을 사용하면 이런 부분을 자동으로 처리할 수 있다.
<div>판매 여부</div> <div>
<div class="form-check">
<input type="checkbox" id="open" th:field="*{open}" class="form-check-input">
<label for="open" class="form-check-label">판매 오픈</label>
</div>
</div>
th:field="*{open}"
을 사용하면 _open코드를 사용하지않고 객체에 저장된 값을 자동으로 꺼내 체크박스에 반영한다.
주의해야 할 점은 폼에서 th:object="${item}"
을 설정하지 않았다면 th:field="*{open}"
을 사용하면 오류가 발생한다. 이 경우 th:field="${item.open}"
으로 설정해야한다.
@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 특별한 사용법
@ModelAttribute
는 컨트롤러에 있는 별도의 메서드에 적용할 수 있다.
이렇게하면 해당 컨트롤러를 요청할 때 regions
에 반환한 값이 자동으로 모델(model
)에 담기게된다.
<div>
<div>등록 지역</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">서울</label>
</div>
</div>
th:for="${#ids.prev('regions')}"
멀티 체크박스는 같은 이름의 여러 체크박스를 만들 수 있는데, 이런식으로 여러개를 만들면 고유한 값을 가져야 할 id값이 같아진다. id값을 다르게 하기위해 타임리프는 체크박스를 each
루프 안에서 반복해서 만들 때 임의로 숫자를 붙인다.
@ModelAttribute("itemTypes")
public ItemType[] itemTypes() {
return ItemType.values();
}
Enum
타입으로 만든 객체를 values
메서드를 이용해 배열로 만들었다.
<div>
<div>상품 종류</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>
이 역시 HTML로 전달된 Enum
객체의 메서드를 활용해서 각 정보를 사용자에게 보여주고 있다.
이때 라디오 박스에 아무값도 선택하지 않으면 null
값으로 전달된다.
<div>
<div>상품 종류</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>
여기에서는 th:field="${item.itemType}"
으로도 사용이 가능하다는 것을 보여주기 위해 이 방식을 사용했다.
th:object=${item}
이 설정되어있지 않으면 th:field="*{itemType}"
은 사용할 수 없다.
셀렉트 박스는 여러 선택지 중에 하나를 선택할 때 사용할 수 있다.
@ModelAttribute("deliveryCodes")
public List<DeliveryCode> deliveryCodes() {
List<DeliveryCode> deliveryCodes = new ArrayList<>();
deliveryCodes.add(new DeliveryCode("FAST", "빠른 배송"));
deliveryCodes.add(new DeliveryCode("NORMAL", "일반 배송"));
deliveryCodes.add(new DeliveryCode("SLOW", "느린 배송"));
return deliveryCodes;
}
<div>
<div>배송 방식</div>
<select th:field="*{deliveryCode}" class="form-select">
<option value="">==배송 방식 선택==</option>
<option th:each="deliveryCode : ${deliveryCodes}" th:value="$
{deliveryCode.code}"
th:text="${deliveryCode.displayName}">FAST</option>
</select>
</div>
출처: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard