스프링 MVC 1편에서 만들었던 상품 관리 프로젝트를 다듬어서 스프링 MVC를 깊이있게 알아보자!
🔗 코드 확인하기
타임리프는 크게 2가지 매뉴얼을 제공한다.
타임리프는 스프링 없이도 동작하지만,
스프링과 통합을 위한 다양한 기능을 편리하게 제공한다!
${@myBean.doSomething()}
처럼 스프링 빈 호출 지원th:object
(기능 강화, 폼 커맨드 객체 선택)th:field
, th:errors
, th:errorclass
checkbox
, 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.html
th: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
의 특별한 사용법을 적용한다.