참고
Spring Boot & Thymeleaf 시리즈는 김영한 님의 "스프링 MVC 2편 - 백엔드 웹 개발 활용 기술" 강의를 정리한 글입니다. 글에 첨부된 사진은 해당 강의의 강의 자료에서 캡쳐한 것입니다. 제 Github에만 올려뒀다가, 정보 공유와 강의 홍보(?)를 위해 블로그에도 업로드합니다.
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의
웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있
www.inflearn.com
마크다운 형식으로 작성한 글을 블로그에 다시 올리는 거라 가독성이 많이 떨어집니다. 조금더 편하게 보시려면 아래의 Github repository에서 보시면 됩니다.
GitHub - Kloong1/TIL: Today I Learned.
Today I Learned. Contribute to Kloong1/TIL development by creating an account on GitHub.
github.com
타임리프 - 입력 폼 처리
기본 HTML Form 대신 타임리프가 제공하는 입력 폼 기능을 적용해서 기존 프로젝트를 개선해보자.
th:object
: 커맨드 객체를 지정한다.*{...}
: 선택 변수 식이라고 한다.th:object
에서 선택한 객체에 접근한다.th:field
: HTML 태그의id
,name
,value
속성을 자동으로 처리해준다.
적용 결과 미리 보기
타임리프 입력 폼 적용 전 HTML Form
<form action="item.html" th:action method="post">
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control" placeholder="이름을 입력하세요">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control" placeholder="가격을 입력하세요">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="form-control" placeholder="수량을 입력하세요">
</div>
<!-- 중략 -->
</form>
th:action
외에는 타임리프가 적용된 부분이 없다.id="..." name="..."
이 중복되어서 나타난다.
타임리프 입력 폼 적용 후 HTML Form
<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>
<!-- 중략 -->
</form>
- 타임리프가 지원하는
th:object
와th:field
가 적용되었다. - 중복되는 속성인
id="..." name="..."
가 없어졌다.
타임리프 입력 폼 적용 방법
th:object
로 Model에서 오브젝트를 꺼내 커맨드 객체로 지정할 수 있다. 따라서 컨트롤러에서 해당 오브젝트를 넘겨줘야 한다. 상품 등록 폼에 타임리프를 적용하려고 하는 상황이기 때문에, 데이터가 없는 빈 상품 오브젝트를 만들어서 뷰에 넘겨줘야 한다.
FormItemController.java 변경
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("item", new Item());
return "form/addForm";
}
item
이라는 이름을 가진 빈Item
객체를 넘겨준다.
form/addForm.html 의 HTML Form 에 타임리프 적용
<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>
<!-- 중략 -->
</form>
th:object="${item}"
<form>
태그 내부에서 사용할 커맨드 객체를 지정한다.- 선택 변수 식
*{...}
을 사용하면 해당 객체에 편리하게 접근할 수 있다.
th:field="*{itemName}"
- 선택 변수 식
*{...}
을 사용하여th:object
에서 지정한 객체에 접근했다. *{itemName}
은th:object=${item}
에 의해${item.itemName}
과 같은 의미를 가진다.
- 선택 변수 식
th:field
는id
,name
,value
속성을 모두 자동으로 만들어준다.id
:th:field
에서 지정한 변수 이름과 같다.id="itemName"
으로 렌더링된다.name
:th:field
에서 지정한 변수 이름과 같다.name="itemName"
으로 렌더링된다.value
:th:field
에서 지정한 변수의 값을 사용한다. 컨트롤러에서 빈 객체를 넘겨줬으므로value=""
으로 렌더링된다.
상품 수정 폼에 타임리프 적용
상품 등록 폼에서는 뷰에 빈 Item
객체를 넘겨줬다. 하지만 상품 수정 폼에서는 데이터가 존재하는 Item
객체를 뷰에 넘겨줘야 한다. 이 때 th:field
에 의해 넘겨받은 객체의 값을 가지고 value
속성을 렌더링하므로 수정 폼을 더 편하게 만들 수 있다.
FormItemController.java 그대로 유지
@GetMapping("/{itemId}/edit")
public String editForm(@PathVariable Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "form/editForm";
}
- 이미 저장되어있는
Item
객체를 뷰에 넘겨준다.
form/editForm.html 타임리프 적용 전
<form action="item.html" th:action method="post">
<div>
<label for="id">상품 ID</label>
<input type="text" id="id" name="id" class="form-control" value="1" th:value="${item.id}" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}">
</div>
<!-- 중략 -->
</form>
- 등록 폼과 마찬가지로
id="..." name="..."
가 중복되어 나타난다. - 넘겨받은
Item
객체의 기존 값을 화면에 표시하기 위해value=${item.xxx}
속성을 사용한다. 문제는 이 속성도id
와name
처럼 중복되어 나타난다.
form/editForm.html 타임리프 적용 후
<form action="item.html" th:action th:object="${item}" method="post">
<div>
<label for="id">상품 ID</label>
<input type="text" class="form-control" th:field="*{id}" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" class="form-control" th:field="*{itemName}">
</div>
<div>
<label for="price">가격</label>
<input type="text" class="form-control" th:field="*{price}">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" class="form-control" th:field="*{quantity}">
</div>
th:field
에 의해id="..." name="..." value="..."
의 중복이 전부 제거되었다.- 개발자 입장에서 HTML Form을 만드는 일이 매우 편리해졌다.
- 심지어 멤버 변수 이름으로 접근하기 때문에 오타가 나면 IDE의 도움으로 즉각 확인이 가능하다.
- IDE가 아니더라도 오타가 나면 렌더링에 실패해서 사용자에게 에러 페이지를 반환하기 때문에, 로그를 따로 확인해 볼 필요 없이 실행 시켜보기만 해도 에러가 났다는 사실을 바로 확인할 수 있다.
정리
th:object
,th:field
덕분에 폼을 개발할 때 약간의 편리함을 얻었다.- 사실 이것의 진짜 위력은 뒤에 설명할 검증(Validation)에서 나타난다.
- 이후 검증 부분에서 폼 처리와 관련된 부분을 더 깊이있게 알아보자.
'Spring > Spring Boot & Thymeleaf' 카테고리의 다른 글
[Spring Boot & Thymeleaf] 20. 체크 박스 단일 선택 (0) | 2022.10.24 |
---|---|
[Spring Boot & Thymeleaf] 19. 체크 박스, 라디오 버튼, 셀렉트 박스 (1) (0) | 2022.10.24 |
[Spring Boot & Thymeleaf] 17. 스프링 통합과 HTML Form (0) | 2022.10.24 |
[Spring Boot & Thymeleaf] 16. 템플릿 레이아웃 (0) | 2022.10.24 |
[Spring Boot & Thymeleaf] 15. 템플릿 조각 (0) | 2022.10.24 |
댓글