Thymeleaf
는 웹서비스 제작을 위한 서버사이드의 자바 템플릿 엔진이다. WAS 혹은 웹서버가 구동되지 않더라도 HTML 파일이 브라우저에 올바르게 표시되도록 하여 개발과정에서 더 강력한 협업을 가능하게 한다. 보통 Spring Framework
과 같은 HTML5 JVM 웹 개발에 이상적이며, 홈페이지에서도 Thymeleaf + spring 문서가 별도로 존재한다.
대략 아래와 같은 회원입력 폼을 만들어보려 한다. bootstrap, spring boot, Thymeleaf
를 사용했으며, 기본적으로 제공된 예시를 바탕으로 진행했으니 자세한 사항은 여기를 클릭해서 참고한다.
Model
html 파일로 뷰(view)를 먼저 만들어야 할거 같지만, 화면과 웹 컨트롤러간에 주고받을 데이터의 구조를 설계하는것을 먼저 만드는 편이다. 화면에서 입력받거나 조회해서 보여줘야 할 데이터를 정의하고, 단건인지 다건인지도 고려해서 정의한다. MemberControllerVo
가 Thymeleaf 뷰에서 매핑될 객체이 구조를 잘 눈여겨 봐야 한다.
public class MemberControllerVo {
private MemberBsc member;
private List<ContactBsc> contacts;
//...get/set 메소드 생략..
}
public class ContactBsc {
private String memberId; // 고객ID
private String relationCd; // 관계구분
private String contactName; // 연락처명
private String phoneNumber; // 연락처번호
//...get/set 메소드 생략..
}
public class MemberBsc {
private String memberId; // 고객ID
private String memberName; // 이름
private String genderCd; // 성별
private String birthDt; // 생년월일
private String signupDt; // 가입일자
private String signupReasonCd; // 가입사유
private String information; // 비고
//...get/set 메소드 생략..
}
Controller
이렇게 정의한 모델들을 기반으로 웹페이지에 데이터를 보내기 위해서 컨트롤러에서 객체를 만든다. 지금 직접 DB에 연결해서 조회하는 부분까지는 구현하지 않고, 빈 폼(form)을 만들기 위한 최소한의 객체 생성만 진행한다. memberInfo
이름으로 속성값을 지정한 걸 눈여겨보자. 그리고 test05
는 springboot 에서 템플릿 파일인 test05.html
을 의미한다.
@GetMapping(value = "/signup")
public String signupForm(String id, Model model) {
MemberControllerVo memberControllerVo =
new MemberControllerVo();
memberControllerVo.setMember(new MemberBsc());
List<ContactBsc> contactBscs = new ArrayList<ContactBsc>();
contactBscs.add(new ContactBsc());
memberControllerVo.setContacts(contactBscs);
model.addAttribute("memberInfo", memberControllerVo);
return "test05";
}
View
보통 Thymeleaf 에서 값을 바인딩 하기 위해서는, 기본적으로 th:value
, th:text
대략 이런 문법을 사용해서 값을 연결할 수 있는데, html 상의 form 내에서의 input, select, textarea
등의 입력부에는 th:field
를 사용하는게 좋다. th:field
속성은 input, select, textarea
각 태그에 연결되어 있는지 여부에 따라 최적으로 셋팅되고, input 태그의 타입유형에 따라도 다르게 작동된다고 한다.
아까 컨트롤러에서 정의한 memberInfo
를 form 태그내에 th:object
로 정의한다. 그리고 그 내부에 있는 input 태그에는 th:field
에 *{..}
표현식으로 속성을 매핑한다. * 는 이미 상위에 정의된 th:object
기준으로 하위 속성을 정의할 때 사용한다.
<form action="#" method="post"
th:action="@{/signup}"
th:object="${memberInfo}">
<input id="name" type="text"
th:field="*{member.memberName}">
</form>
성별을 입력받는 select 태그에도 동일하게 th:field="*{member.genderCd}
로 셋팅한다.
<select id="gender" th:field="*{member.genderCd}">
<option disabled value="">-</option>
<option value="M">남</option>
<option value="F">여</option>
</select>
loop 로 동적인 input 태그를 생성하는 예시이다. + 버튼으로 입력하는란을 동적으로 행추가 할 수 있도록 기능을 만들었다. th:field
를 사용할 때 주의할 점은 th:object
정의된 명칭을 기준으로 th:field
에 바인딩해야 한다. th:field=${ctt.phoneNumber}
로 하게되면 에러가 발생하니, loop 변수를 직접사용하지말고, index 만 사용해서 직접 접근하도록 한다.
<div th:each="ctt,iterStat : *{contacts}">
<input class="form-control" id="parentsTel1" type="text"
th:field="*{contacts[__${iterStat.index}__].phoneNumber}">
</div>
이 두번째 변수인 iterStat
은 위치가 중요한거지 본인이 원하는 이름으로 정하면 된다. 이 변수를 가지고 index, count, size, current, even, odd, first, last
속성을 사용할 수 있게 되며, 간결한 loop 처리를 할 수 있도록 도와준다. 자세한 내용은 여기를 클릭해서 확인한다.