-
[스프링MVC - 2편] 타임리프 스프링 통합 (1)스프링&스프링부트 2025. 2. 1. 17:45
타임리프 스프링 통합
타임리프는 스프링 없이도 동작하지만, 스프링과 통합을 위한 다양한 기능을 편리하게 제공한다
스프링 통합으로 추가되는 기능들
- 스프링의 SpringEL 문법 통합
- ${@myBean.doSomething()}처럼 스프링 빈 호출 지원
- 편리한 폼 관리를 위한 추가 속성
- th:object (기능 강화, 폼 커맨드 객체 선택)
- th:field, th:errors, th:errorclass
- 폼 컴포넌트 기능
- checkbox, radio button, List 등을 편리하게 사용할 수 있는 기능 지원
- 스프링의 메시지, 국제화 기능의 편리한 통합
- 스프링의 검증, 오류 처리 통합
- 스프링의 변환 서비스 통합(ConversionService)
1. 입력 폼 처리
- 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}" />
2. 등록 폼
th:object를 적용하려면 먼저 해당 오브젝트 정보를 넘겨주어야 한다
등록 폼이기 때문에 데이터가 비어있는 빈 오브젝트를 만들어서 뷰에 전달한다
등록 폼
FormItemController
@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> '''
- th:object="${item}" :<form>에서 사용할 객체를 지정한다. 선택 변수 식(*{...})을 적용할 수 있다
- th:field="*{itemName}"
- *{itemName}는 선택 변수 식을 사용했는데, ${item.itemName}과 같다 th:object로 item을 선택했기 때문에 선택 변수 식을 적용할 수 있다
- th:field는 id, name, value 속성을 모두 자동으로 만들어준다
- 렌더링 전 : <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요" >
- 렌더링 후 : <input type="text" id="itemName" class="form-control" placeholder="이름을 입력하세요" name="itemName" value="">
수정폼
@GetMapping("/{itemId}/edit") public String editForm(@PathVariable Long itemId, Model model) { Item item = itemRepository.findById(itemId); model.addAttribute("item", item); return "form/editForm"; }
<form action="item.html" th:action th:object="${item}" method="post"> <div> <label for="id">상품 ID</label> <input type="text" id="id" th:field="*{id}" class="form-control" readonly> </div> <div> <label for="itemName">상품명</label> <input type="text" id="itemName" th:field="*{itemName}" class="form-control"> </div> '''
요구사항 추가
- 판매 여부 : 판매 오픈 여부 / 체크 박스로 선택할 수 있다
- 등록 지역 : 서울, 부산, 제주 / 체크 박스로 다중 선택할 수 있다
- 상품 종류 : 도서, 식품, 기타 / 라디오 버튼으로 하나만 선택할 수 있다
- 배송 방식 : 빠른 배송, 일반 배송, 느린 배송 / 셀렉트 박스로 하나만 선택할 수 있다
1. ItemType - 상품 종류 enum 추가
2. 배송 방식 - DeliveryCode 추가
3. Item - 상품 필드 추가
체크 박스 - 단일1 ( 단순 HTML 체크박스)
<!-- single checkbox --> <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 Form에서 open=on이라는 값이 넘어간다
스프링은 on이라는 문자를 true 타입으로 변환해준다
문제 : 체크 박스를 선택하지 않을 때
HTML에서 체크 박스를 선택하지 않고 폼을 전송하면 open이라는 필드 자체가 서버로 전송되지 않는다
HTML checkbox는 선택이 안되면 클라이언트에서 서버로 값 자체를 보내지 않는다
수정의 경우에는 상황에 따라서 이 방식이 문제가 될 수 있다
사용자가 의도적으로 체크되어 있던 값을 체크를 해제해도 저장시 아무 값도 넘어가지 않기 때문에, 서버 구현에 따라서 값이 오지 않은 것으로 판단해서 값을 변경하지 않을 수도 있다
해결 : 체크 해제를 인식하기 위한 히든 필드 <input type="hidden" name="_open" value="on"/>
<!-- single checkbox --> <div>판매 여부</div> <div> <div class="form-check"> <input type="checkbox" id="open" name="open" class="form-check-input"> <!-- 히든 필드 추가 --> <input type="hidden" name="_open" value="on"/> <label for="open" class="form-check-label">판매 오픈</label> </div> </div>
체크 박스 체크
- open=on&_open=on
- 체크 박스를 체크하면 스프링 MVC가 open에 값이 있는 것을 확인하고 사용한다
- 이때 _open은 무시한다
open=on&_open=on`
체크 박스를 체크하면 스프링 MVC가 `open` 에 값이 있는 것을 확인하고 사용한다. 이때 `_open` 은 무시한다.
**체크 박스 미체크**
`_open=on`
체크 박스를 체크하지 않으면 스프링 MVC가 `_open` 만 있는 것을 확인하고, `open` 의 값이 체크되지 않았다고 인식한
다.
이 경우 서버에서 `Boolean` 타입을 찍어보면 결과가 `null` 이 아니라 `false` 인 것을 확인할 수 있다.
체크 박스 미체크
- _open=on
- 체크 박스를 체크하지 않으면 스프링 MVC가 _open만 있는 것을 확인하고, open의 값이 체크되지 않았다고 인식한다
- 이 경우 서버에서 Boolean 타입을 찍어보면 결과가 null이 아니라 false이다
체크 박스 - 단일2 ( 타임리프)
<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>
타임리프를 사용하면 체크 박스의 히든 필드와 관련된 부분도 함께 해결해준다
HTML 생성 결과를 보면 히든 필드 부분이 자동으로 생성되어 있다
상품 상세에 적용 - item.html
<div>판매 여부</div> <div> <div class="form-check"> <input type="checkbox" id="open" th:field="${item.open}" class="form-check-input" disabled> <label for="open" class="form-check-label">판매오픈</label> </div> </div>
타임리프의 체크 확인 - checked="checked"
체크 박스에서 판매 여부를 선택해서 저장하면, 조회시에 checked 속성이 추가되었다
타임리프의 th:field를 사용하면, 값이 true인 경우 체크를 자동으로 처리해 준다
728x90'스프링&스프링부트' 카테고리의 다른 글
[스프링MVC - 2편] 타임리프 스프링 통합 (2) (1) 2025.02.02 [스프링MVC - 2편] 타임리프 스프링 통합 (2) (0) 2025.02.02 [스프링MVC - 2편] 타임리프 기본기능 (2) (1) 2025.02.01 [스프링MVC - 2편] 타임리프 기본기능 (1) (0) 2025.01.31 [스프링MVC - 1편] 스프링 MVC - 웹 페이지 만들기 (2) (0) 2025.01.30