셀렉트 박스
이번 게시글에서는 타임리프를 통해 셀렉트 박스를 처리하는 방법에 대해 알아보자.
예시 코드
도메인: DeliveryCode
/**
 * FAST: 빠른 배송  * NORMAL: 일반 배송  * SLOW: 느린 배송
 */
@Data
@AllArgsConstructor
public class DeliveryCode {
	private String code;
	private String displayName;
}
도메인: Item
@Data
public class Item {
    private Long id;
    private String itemName;
    private Integer price;
    private Integer quantity;
    private Boolean open; //판매 여부
		private List<String> regions; //등록 지역
		private ItemType itemType; //상품 종류
		private String deliveryCode; //배송 방식
    public Item() {
    }
    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}
컨트롤러
@ModelAttribute 애너테이션이 어떻게 사용되었는지 보자.
@Slf4j
@Controller
@RequestMapping("/form/items")
@RequiredArgsConstructor
public class FormItemController {
	private final ItemRepository itemRepository;
	@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;
	}
// ------------- 상품 객체 추가를 위한 메서드 (위에서 살펴본 메서드들) -----------------
	@GetMapping("/add")
	public String addForm(Model model) {
		model.addAttribute("item", new Item());
		return "form/addForm";
	}
	
	@PostMapping("/add")
	public String addItem(@ModelAttribute Item item, RedirectAttributes redirectAttributes) {
		log.info("item.open={}", item.getOpen());
		Item savedItem = itemRepository.save(item);
		redirectAttributes.addAttribute("itemId", savedItem.getId());
		redirectAttributes.addAttribute("status", true);
		return "redirect:/form/items/{itemId}";
	}
}
@ModelAttribute 는 다른 메서드가 호출될 때마다, 본인 메서드를 실행하여 반환값을 model 객체에 바인딩한다. 따라서 List<DeliveryCode> deliveryCodes = new ArrayList<>(); 를 통해, 다른 메서드가 호출될 때마다 ArrayList 객체가 생성된다. 그러므로, 다른 곳에서 미리 생성해둔 뒤 반환하는 구조로 설계해야 더 효율적이지만, 예시의 간소화를 위해 그대로 진행하겠다.
타임리프
<!DOCTYPE html>
<html	xmlns:th="http:// www.thymeleaf.org">
<head>
	<title>상품등록 폼</title>
</head>
<body>
	<form action="item.html" th:action th:object="${item}" method="post">
		<div>
			<label for="itemName">상품명</label>
			<input type="text" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
		</div>
		<div>
			<label for="price">가격</label>
			<input type="text" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요">
		</div>
		<div>
			<label for="quantity">수량</label>
			<input type="text" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요">
		</div>
		<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>
	<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>
	<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>
	<!--------------------- 주목!!! ------------------------------->
	<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>
	<!------------------------------------------------------------->
	<button type="submit">상품 등록</button>
</form>
</body>
</html>
상세 설명
타임리프
<select th:field="*{deliveryCode}" ... >th:field="*{deliveryCode}"은 컨트롤러로부터 전달받은item객체의deliveryCode프로퍼티를 의미한다.id="itemType#"(동적으로 생성된다.),name="itemType"이 생성된다.
<option th:each="deliveryCode : ${deliveryCodes}" th:value="${deliveryCode.code}" th:text="${deliveryCode.displayName}">th:each="deliveryCode : ${deliveryCodes}"을 통해, 컨트롤러로부터 전달받은deliveryCodes객체를 하나씩 꺼내며 반복한다.
타임리프의 선택 확인
<option> 태그의 th:value="${deliveryCode.code}" 와, <select> 태그의 th:field="*{deliveryCode}" 의 값을 비교하여 selected 옵션을 자동적으로 추가해준다.
- 본 게시글은 김영한님의 강의를 토대로 정리한 글입니다.
 - 더 자세한 내용을 알고 싶으신 분들이 계신다면, 해당 강의를 수강하시는 것을 추천드립니다.
 
		