[Spring Web MVC] Thymeleaf (2)
타임리프는 스프링 없이도 잘 동작하지만, 스프링과의 통합을 위한 편리한 기능들을 많이 제공한다.
기능을 하나하나 살펴보자.
입력 폼 처리
<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="이름을 입력하세요">
타임리프를 사용하기 전 모델을 통해 item 객체를 넘겨준다.
*{...} 은 선택 변수 식으로 th:object 에서 선택한 객체에 접근한다. ( ${item.itemName} 으로 작성해도 된다. )
th:field 는 폼에서 id / name / value 속성을 자동으로 만들어준다. (th:field 에서 지정한 이름으로 설정된다.)
<input type="checkbox" id="open" name="open" class="form-check-input">
HTML 폼에 체크박스가 있는 경우 전송해서 POST 방식으로 서버에게 요청하면 서버에서 요청 값을 확인 시 체크박스가 선택된 경우 해당 값이 true 로, 체크박스가 선택되지 않은 경우 해당 값이 null로 초기화 돼 있다.
HTML 체크박스는 선택되지 않으면 서버로 값 자체를 넘기지 않는다.
새로 입력할 때는 그렇다 쳐도 값을 수정 시 이런 상황이 발생하면 이런 로직이 문제가 될 수 있다.
스프링 MVC 는 값의 유무에 상관없이 전송될 때 무조건 함께 전송되는 히든 필드를 하나 만들어서 이런 문제를 해결한다.
<input type="checkbox" id="open" name="open" class="form-check-input">
<input type="hidden" name="_open" value="on"/> <!-- 히든 필드 추가 -->
히든 필드의 값과 체크박스의 값을 비교해서 의도한대로 동작할 수 있도록 한다.
타임리프가 제공하는 기능을 사용하면 이 작업도 간단하게 처리할 수 있다.
<input type="checkbox" id="open" th:field="*{open}" class="form-checkinput">
(th:object 로 사용할 객체를 지정한 상태이다.)
th:field를 사용하면 체크박스의 히든 필드 관련 부분도 함께 해결해준다.
<input type="checkbox" id="open" class="form-check-input" name="open" value="true">
<input type="hidden" name="_open" value="on"/>
(렌더링 된 HTML 코드)
렌더링 시 th:field 가 히든 필드를 알아서 만들어준다.
<input type="checkbox" id="open" th:field="${item.open}" class="formcheck-input" disabled>
그리고 이렇게 th:field 와 disabled 속성을 함께 사용하면
<input type="checkbox" id="open" class="form-check-input" disabled name="open" value="true" checked="checked">
타임리프를 통해 렌더링 시 checked 속성을 만들어준다.
값이 참이면 checked를 넣어주고, 값이 거짓이면 check를 넣지 않는 방식으로 동작한다.
타임리프 없이 구현하려면 코드도 길어지고 지저분해진다.
타임리프가 제공하는 다양한 편의 기능을 사용해 웹 페이지를 설계하자.
하나 이상을 체크할 수 있는 멀티 체크박스를 사용해보자.
이 때 여러 페이지에 멀티 체크박스 관련된 데이터를 추가해야 하는데, @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 에서 반환한 값이 모델에 담긴다.
<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>
모델을 통해 넘어간 regions 를 활용해서 HTML 을 렌더링한다.
regions를 순회하면서 뷰를 렌더링하는데, th:for="${#ids.prev('regions')}" 를 통해 타임리프가 각각 체크박스의 아이디를 중복 없이 생성해준다. (이름은 같아도 되지만, 아이디는 달라야 한다.)
HTML 의 id가 타임리프에 의해 동적으로 만들어지기 때문에 ids.prev(..) ids.next(..) 처럼 id 값을 동적으로 생성한다.
여러 가지 선택지 중 하나만 선택해야 할 때 사용하는 라디오 버튼을 사용해보자.
public enum ItemType {
BOOK("도서"), FOOD("음식"), ETC("기타");
private final String description;
ItemType(String description) {
this.description = description;
}
}
자바의 enum을 사용해서 라디오 버튼을 구현한다.
@ModelAttribute("itemTypes")
public ItemType[] itemTypes(){
return ItemType.values();
}
이전과 같이 @ModelAttribute 애너테이션으로 데이터를 넘겨주자. ItemType.values() 를 사용하면 해당 enum의 모든 정보를 배열로 반환한다.
<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>
모델을 통해 넘어간 enum을 바탕으로 HTML 을 렌더링한다.
라디오박스는 히든 필드를 사용하지 않는다.
체크박스는 수정 할 때 체크를 풀고 전송하면 아무 값도 넘어가지 않아서 히든 필드가 필요했는데, 라디오박스는 버튼이 선택된 상태면 수정 시에 무조건 하나를 선택해야해서 히든 필드가 필요 없다.
<div th:each="type : ${T(hello.itemservice.domain.item.ItemType).values()}">
타임리프에서는 enum을 사용할 때 모델에 값을 넘기지 않고도 위와 같이 enum을 선언해두면 enum을 사용할 수 있다.
그런데 모델을 통해 넘기는 편이 더 깔끔하니.. 이런 게 있다 정도로만 알고 넘어가자.
여러 선택지 중에서 하나를 선택할 때 셀렉트 박스를 사용한다. (체크박스 형식이 아님)
자바 객체를 사용해 셀렉트 박스를 사용해보자.
@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;
}
@ModelAttribute 애너테이션으로 자바 객체 타입의 데이터를 모델에 넘겨줬다.
<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>
select 문법으로 시작한다.
나머지는 체크박스 / 라디오 박스와 같다.
'Spring > Spring Web MVC' 카테고리의 다른 글
[Spring Web MVC] 데이터 검증 (0) | 2022.08.22 |
---|---|
[Spring Web MVC] 메세지와 국제화 (0) | 2022.08.20 |
[Spring Web MVC] Thymeleaf (1) (0) | 2022.08.19 |
[Spring Web MVC] Spring MVC와 Thymeleaf 예시 (0) | 2022.08.18 |
[Spring Web MVC] 응답 정보 다루기 (0) | 2022.08.17 |
댓글
이 글 공유하기
다른 글
-
[Spring Web MVC] 데이터 검증
[Spring Web MVC] 데이터 검증
2022.08.22 -
[Spring Web MVC] 메세지와 국제화
[Spring Web MVC] 메세지와 국제화
2022.08.20 -
[Spring Web MVC] Thymeleaf (1)
[Spring Web MVC] Thymeleaf (1)
2022.08.19 -
[Spring Web MVC] Spring MVC와 Thymeleaf 예시
[Spring Web MVC] Spring MVC와 Thymeleaf 예시
2022.08.18