
스프링 MVC 1편에서 만들었던 상품 관리 프로젝트를 다듬어서 스프링 MVC를 깊이있게 알아보자!
🔗 코드 확인하기
타임리프는 크게 2가지 매뉴얼을 제공한다.
타임리프는 스프링 없이도 동작하지만,
스프링과 통합을 위한 다양한 기능을 편리하게 제공한다!
${@myBean.doSomething()}처럼 스프링 빈 호출 지원th:object (기능 강화, 폼 커맨드 객체 선택)th:field, th:errors, th:errorclasscheckbox, radio button, List 등을 편리하게 사용할 수 있는 기능 지원build.gradle에 다음 코드 추가해주기
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
타임리프가 제공하는 입력 폼 기능을 이용하여 기존 프로젝트의 폼 코드를 효율적으로 개선할 수 있다!
th:object: 커맨드 객체를 지정한다.*{...}: 선택 변수 식. th:object 에서 선택한 객체에 접근한다.th:field: HTML 태그의 id, name, value 속성을 자동으로 처리해준다.<input type="text" th:field="*{itemName}" />
<input type="text" id="itemName" name="itemName" th:value="*{itemName}" />

th:object, th:field를 이용하여 폼 개발이 조금 편리해졌다!
사실 이 기능들의 위력은 뒤에 배울 검증(Validation)에서 나타난다!
타임리프를 사용해서 폼에서 체크박스, 라디오 버튼, 셀렉트 박스를 편리하게 사용하는 방법에 대해 알아보자!
기존 상품 서비스에 다음 요구사항이 추가되었다.

ItemType - 상품 종류상품 종류는 ENUM을 사용한다.
DeliveryCode - 배송 방식배송 방식은 DeliveryCode라는 클래스 사용!
code는 FAST 같은 시스템에서 전달하는 값이고, displayName은 빠른 배송 같은 고객에게 보여지는 값이다.Item - 상품ENUM, 클래스, String 같은 다양한 상황을 준비했다.
각각의 상황에 어떻게 폼의 데이터를 받을 수 있는지 하나씩 알아보자.
HTML 체크 박스 주의점

HTML에서 체크 박스를 선택❌ 폼 전송 → open 필드 자체가 서버로 전송되지 않는다!
이것은 우리가 원하는 결과가 아니다! 선택하지 않았을 때 false가 출력되기를 원한다.
위의 문제를 해결하기 위해 스프링 MVC는 히든 필드를 하나 만든다!
_open처럼 "_ + 기존 체크박스 이름 "으로 만든 히든 필드를 전송하여 체크를 해제했음을 인식하도록 한다.
이것은 히든 필드는 항상 전송된다는 특징을 이용한 방법으로,
체크를 해제한 경우 여기에서 open은 전송되지 않고 _open만 전송되어,
스프링 MVC는 체크를 해제했다고 판단할 수 있게 된다!


📌 정리
1. 체크박스 체크 -
open=on&_open=on: 체크박스를 체크하면 스프링 MVC가
open에 값이 있는 것을 확인하고 사용한다. 이때_open은 무시한다.2. 체크박스 미체크 -
_open=on: 체크박스를 체크하지 않으면 스프링 MVC가
_open만 있는 것을 확인하고,open의 값이 체크되지 않았다고 인식한다.
위의 실행화면에서 볼 수 있듯이, 서버에서Boolean타입을 찍어보면open의 값이null이 아닌false로 나온다!
하지만 매번 사용할 때마다 히든 필드를 추가하는 것은 매~~우 번거로운 일이다.
타임리프가 제공하는 폼 기능을 사용하면 이런 부분을 자동으로 처리할 수 있다!
<!-- single checkbox -->
<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>
체크박스의 기존 코드를 제거하고 타임리프가 제공하는 체크박스 코드로 변경하자


타임리프를 사용하면 히든 필드 부분이 자동으로 생성된다!
이번에는 체크박스를 멀티로 사용해서, 하나 이상을 체크할 수 있도록 해보자!
✔ 등록 지역
- 서울, 부산, 제주
- 체크 박스로 다중 선택할 수 있다.
@ModelAttribute의 특별한 사용법등록 폼, 상세화면, 수정 폼에서 모두 서울, 부산, 제주라는 체크 박스를 반복해서 보여줘야 한다.
이렇게 하려면 각각의 컨트롤러에서 model.addAttribute() 을 사용해서 체크 박스를 구성하는 데이터를 반복해서 넣어주어야 한다.
@ModelAttribute는 이렇게 컨트롤러에 있는 별도의 메서드에 적용할 수 있다.
@ModelAttribute("regions")
public Map<String, String> regions() {
Map<String, String> regions = new LinkedHashMap<>();
regions.put("SEOUL", "서울");
regions.put("BUSAN", "부산");
regions.put("JEJU", "제주");
return regions;
}
해당 컨트롤러를 요청할 때 regions에서 반환한 값이 자동으로 모델(model)에 담기게 된다.
물론 이렇게 사용하지 않고, 각각의 컨트롤러 메서드에서 모델에 직접 데이터를 담아서 처리해도 된다!
addForm.htmlth:for="${#ids.prev('regions')}"
멀티 체크박스는 같은 이름의 여러 체크박스를 만들 수 있다.
그런데 이렇게 반복해서 HTML 태그를 생성할 때,
생성된 HTML 태그 속성에서 name은 같아도 되지만, id 는 모두 달라야 한다.
이를 위해 타임리프는 체크박스를 each 루프 안에서 반복해서 만들 때,
임의로 1, 2, 3 숫자를 뒤에 붙여준다.


라디오 버튼은 여러 선택지 중에 하나를 선택할 때 사용할 수 있다.
✔ 상품 종류
- 도서, 식품, 기타
- 라디오 버튼으로 하나만 선택할 수 있다.
FormItemController@ModelAttribute("itemTypes")
public ItemType[] itemTypes() {
return ItemType.values();
}
itemTypes를 등록 폼, 조회, 수정 폼에서 모두 사용하므로 @ModelAttribute의 특별한 사용법을 적용!ItemType.values()를 사용하면 해당 ENUM의 모든 정보를 배열로 반환한다. [BOOK, FOOD, ETC]

⭐ 라디오 버튼
- 라디오 버튼은 아무것도 선택하지 않을 경우, 아무 값도 넘어가지 않아
null이 된다.- 라디오 버튼은 이미 선택이 되어 있다면, 수정시에도 항상 하나를 선택하도록 되어있기 때문에 별도의 히든필드를 사용할 필요가 없다!
셀렉트 박스는 여러 선택지 중에 하나를 선택할 때 사용할 수 있다.
✔ 배송 방식
- 빠른 배송 / 일반 배송 / 느린 배송
- 셀렉트 박스로 하나만 선택할 수 있다.
FormItemController@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;
}
DeliveryCode를 등록 폼, 조회, 수정 폼에서 모두 사용하므로 마찬가지로 @ModelAttribute의 특별한 사용법을 적용한다.

