[Thymeleaf] 타임리프와 스프링 통합

타임리프는 스프링과 통합을 위한 다양한 기능을 제공한다.

 

 

타임리프 템플릿 엔진 스프링 빈 등록

스프링 부트는 build.gradle에 코드를 추가해주면 타임리프 템플릿 엔진을 스프링 빈에 등록하고, 타임리프용 뷰 리졸버를 스프링 빈으로 등록할 수 있게 해준다. (자동화 가능하다)

implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

 

 

입력 폼 활용

<form action="item.html" th:action th:object="${item}" method="post">
        <div>
            <label for="itemName">name</label>
            <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="input name">
        </div>
</form>

th:object를 적용하기 위해서는 Controller부분에서 model을 이용해서 오브젝트를 뷰로 전달해주고, 뷰에서는 form태그에 th:action과 th:object를 적용한 후 밑에서 타임리프 문법을 이용해서 전달받은 오브젝트로 사용하면 된다.

또한 th:object의 적용 범위는 form태그 안에서만 유효하며, id나 name값도 생략 가능하게 한다(자동완성 시켜줌)

 

 

- 체크박스, 타임리프 이용 체크박스

<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>

> hidden 필드를 이용한 체크박스 값 조정

<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>

> 타임리프를 이용한 체크박스 값 조정

 일반적으로 checkbox를 사용하면 체크되지 않을 경우 id값이 아예 넘어오지 않는다. 따라서 hidden필드를 이용하여 체크되지 않는 경우에 id값이 false로 넘어오게 하는 방법이 필요한데, 그것을 위해서 hidden필드를 이용한다. 하지만 대신 checkbox input필드를 사용할때마다 히든필드를 생성해주어야 하는 번거로움이 있는데, 타임리프를 사용하면 별도의 처리를 하지 않아도 자동으로 hidden필드가 넘어온다.

 

 

 

타임리프 메세지 적용

타임리프의 메세지 표현식 #{...}을 사용하면 스프링의 메세지를 편리하게 조회할 수도 있다.

<div th:text="#{label.item}"></h2>
<div>상품</h2>

> 위와 같이 메세지 표현식을 이용하면 application.properties에 저장해둔 메세지 세팅값에 따라서 label.item값의 적절한 메세지를 messages_*.properties에서 읽어와서 HTML로 변환해준다.

label.item=상품

> messages.properties 모습

 

 

 

스프링 검증 오류 통합 기능

타임리프는 스프링의 BindingResult를 활용해서 편리하게 검증 오류를 표현할 수 있다.

#fields : #fields 로 BindingResult 가 제공하는 검증 오류에 접근할 수 있다.
th:errors : 해당 필드에 오류가 있는 경우에 태그를 출력한다. th:if 의 편의 버전이다.
th:errorclass : th:field 에서 지정한 필드에 오류가 있으면 class 정보를 추가한다
<div th:if="${#fields.hasGlobalErrors()}">
    <p class="field-error" th:each="err : ${#fields.globalErrors()}"
    th:text="${err}">글로벌 오류 메시지</p>
</div>

> BindingResult가 제공하는 글로벌 에러(특정 필드에러가 아닌 것들)를 검사하여, 각각에 대해 출력

<div>
    <label for="itemName" th:text="#{label.item.itemName}">상품명</label>
    <input type="text" id="itemName" th:field="*{itemName}"
           th:errorclass="field-error" class="form-control" placeholder="이름을 입력하세요">
    <div class="field-error" th:errors="*{itemName}">
         상품명 오류
    </div>
 </div>

> 특정 필드에 대한 에러를 출력. 여기서는 item.itemName에 대한 오류를 받아와 출력한다.