본문 바로가기

Spring

[Spring Boot 템플릿 엔진] 타임리프(Thymeleaf) / 표현식 / 출력제어

https://www.thymeleaf.org/

 

 

 

1. 타임리프 ?

스프링 부트를 비롯한 프레임워크에서 JSP 대신 사용하는 '뷰'쪽 템플릿 엔진이다. 쉽게 말하면 템플릿 엔진이라는 게 html 등의 뷰를 만들어주는 앤데, 그 템플릿 엔진 중 하나가 타임리프다. 

 

템플릿 엔진

뼈대가 되는 문서(템플릿)에 가변 데이터를 삽입함으로써 동적으로 문서를 생성하는 구조다. 

 

 

2. 타임리프 템플릿

타임리프는 XHTML이나 HTML5 등으로 작성된 템플릿을 DOM(Document Object Model)으로 변환하고 처리하는 구조로 돼 있으며, '처리 대상의 DOM 노드'와 'DOM 노드에 적용하는 처리'를 th 네임스페이스 속성을 사용해 지정한다. 

 

 

3. 타임리프와 스프링의 연계

타임리프와 스프링 프레임워크를 연계할 때는 타임리프에서 제공하는 모듈을 이용한다. 모듈을 사용하면 스프링 MVC가 JSP용으로 제공하는 태그 라이브러리 같은 기능을 타임리프에서도 사용할 수 있다. 

 

 

 

뷰 리졸버(스프링 컨테이너)가 html을 찾는 과정

 

 

뷰 리졸버(스프링 컨테이너)가 html을 찾는 과정

controller에서 return 값으로 문자를 반환하면 하면 템플릿에서 해당 html을 찾는다. 그러면 스프링에서 뷰 리졸버 'view resolver'가  해당 html을 선택하고 타임리프 템플릿 엔진을 randering 한다. rendering이 끝난 html이 최종적으로 뿌려지게 된다. 

 

 

스프링 부트 템플릿엔진 기본 viewName 매핑 

resources:templates/ + {viewName} +.html

return "home"에는 결국, resources:templates/ + "home" + .html 이 압축되어있다.

 

 

뷰 리졸버 'view resolver'는 스프링 컨테이너에서 스프링 MVC의 뷰를 결정하는 앤데,  타임리프 라이브러리를 사용할 경우 view resolver의 구현체가 타임리프의 뷰 리졸버로 대체된다. 

 

 

4. 타임리프를 이용한 뷰 구현

네임스페이스로 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> 를 부여한다. 

 

 

 

쉽게 설명하려고 타임리프로 구현한 form을 들고와봤다. 

 

th:action ="@{/가야할 경로}"

타임리프를 뷰로 사용한 웹 애플리케이션에서는 링크 대상을 애플리케이션의 요청 대상의 URL(스프링 MVC의 경우에는 컨트롤러의 @RequestMapping 에 지정된 경로)을 지정해야한다.

 3번 라인   th:action="@{/todos}"

 

th:object="${폼 객체의 프로퍼티명}"

폼 클래스에 연결하는 폼 객체의 프로퍼티명 지정 

14번 라인    th:object="${todo}"

 

th:field="${폼클래스의 각 프로퍼티명}"

19번 라인    th:field="*{task}" = "${todo.task}"

 

 

th:text="${출력할 값이 담긴 변수}" 

스프링 MVC 모델에 저장된 값을 HTML에 출력하는 경우 임의의 HTML 요소에 대해 타임리프의 th:text 속성을 이용한다.

 

 

5. 타임리프의 표현식

기본적 표현식

변수식 ${user.firstName} 

타임리프에서는 변수식에 HTTP 세션(#httpSession)과 HTTP 요청(#httpServletRequest)을 비롯한 각종 타임리프가 관리하는 변수에 접근하거나 메서드를 실행할 수 있다. 

 

선택 변수식 *{name}

변수식에서는 ${user.name}, ${user.age}, ${user.tel} 처럼 특정 객체의 프로퍼티에 연속으로 접근하고 싶을 때가 자주 있다. 이러한 경우에는 th:object 속성과 선택 변수식으로 조합해서 사용하면 변수식보다 간단하게 기술할 수 있다. 

HTML요소에 th:object=${user}를 정의해두면 *{name}, *{address}, *{tel} 와 같이 user를 생략한 형태로 기술할 수 있다.

 

메시지식 #{status.reserved.message} 

타임리프에서는 메시지를 키-값으로 관리한다. 메시지의 키 값(status.reserved.message)이으로 메시지 본문을 가져오고 싶을 때 메시지 식을 사용한다. 메시지에 삽입하는 매개변수는 #{home.welcome(${session.user.name})}과 같이 키 값의 뒷부분에 괄호를 붙이고 그 안에 매개변수 값을 나열하면된다. 

 

링크 URL 식 @{/echo} 

타임리프에서는 링크 URL을 이용해 지정한 URL(이 예에서는 /echo)이 시작되는 부분에 컨텍스트 경로를 추가할 수 있다. 예를 들어 컨텍스트 경로가 app이라면 app/echo가 된다.  

 

 

리터럴

문자열을 표현하기 위한 텍스트 리터럴은 작은따옴표로 둘러싼다. 또한 값으로 포함된 작은 따옴표는 '\'로 이스케이프 해야한다. 

  • 텍스트 리터럴 : 'spring framework' , 'I\'m a user'
  • 수치 리터럴 : 0, 1.4, 2021
  • 불린값 리터럴 : true, false
  • Null 리터럴 : null

 

 

기본적인 연산자

  • 산술 연산 : th:text="${price} * ${num}"
  • 논리 연산 : th:if="${not todo.finished}"
  • 마이너스 부호: th:text="-10"
  • 비교 연산 : th:if="${items.count} gt 1"

 

 

타임리프는 마크업 언어이기 때문에 &lt; 등으로 이스케이프해야한다.

  • gt (>)
  • lt (<)
  • ge (>=)
  • le (<=)
  • not (!)
  • eq (==)
  • neq/ne(!=)

 

 

텍스트 연산자

  • 텍스트 추가 th:text=" ' My name is ' + ${username}. "
  • 텍스트 치환 th:text=" | My name is ${username} | "

 

조건 연산자

  • 삼항 연산자 th:class="${row.even}? 'even' : 'odd'"
  • 엘비스 연산자 th:text="${username}? : 'Sam Smith'"

 

 

 

5. HTML 요소의 출력 제어

조건에 따른 출력 여부 제어

  • th:if 속성 값이 참인 경우에만 대상이 되는 HTML 요소를 출력한다.
  • th:unless 속성 값이 거짓인 경우에만 대상이 되는 HTML 요소를 출력한다.
  • th:switch 자식 요소에 기술된 th:case 속성의 값과 비교 평가를 하기 위한 값을 설정한다.
  • th:case 부모 요소의 th:switch 속성 값의 경우에만 대상이 되는 HTML 요소를 출력한다.

 

th:if 예시 

<div th:if="${not #strings.isEmpty(room.remark)}">
	<label>비고</label>
	<span th:text="*{room.remark}">비고가 입력되어 있으면 표시</span>
</div>

// #strings.isEmpty ?
타임리프가 제공하는 문자열을 위한 유틸리티. 문자열이 공백 또는 null인 경우에 참을 반환

 

 

th:switch / th:case 예시

	<div th:switch="*{room.size}">
		<label> 방 크기 </label>
		<span th:case="'L'">대</span>
		<span th:case="'M'">중</span>
		<span th:case="'S'">소</span>
		<span th:case="'*'">불명</span>  // 어느 속성에도 해당하지 않을 때 * 
	</div>

 

 

 

 

반복 출력 제어

지정한 배열 값의 수만큼 HTML 요소를 반복 출력하는 것처럼 출력 반복을 제어할 수 있는 th:each.

th:each에는 다음과 같은 배열에 해당하는 타입을 지정해야한다.

  • java.util.List 구현 클래스
  • java.util.Iterable 구현 클래스
  • java.util.Map 구현 클래스
  • 배열

 

 

반복 출력 시의 메타정보

프로퍼티 설명
index 현재 반복 인덱스(0부터 시작)
count 현재 반복 인덱스(1부터 시작)
size 반복 대상의 총 건수
current 현재 반복 처리에서 취급하는 요소 값
odd 현재 반복 처리에서 홀수 여부를 나타내는 논리 값
even 현재 반복 처리에서 짝수 여부를 나타내는 논리 값
first 현재 반복 처리에서 첫번째 여부를 나타내는 논리 값
last 현재 반복 처리에서 마지막 여부를 나타내는 논리 값

 

 

th:each의 예

<tr th:each="prod : ${products}">
	<td th:text="${prodStat.count}">1</td> 
	<td th:text="${prod.name}">Tomato</td>
	<td th:text="${prod.price}">4980</td>
	<td th:text="${prod.stock == 0? '품절' : prod.stock}">10</td>
</tr>


//2 라인
'반복 대상의 현재 값을 저장하는 변수명: 반복 대상의 배열 값' 형식으로 지정
products 리스트를 대상으로 현재 값을 저장하는 변수명을 prod로 정의

//3 라인
반복에 대한 메타 정보에 접근하려면 타임리프가 묵시적으로 생성한 변수를 이용(변수명에 접미사 Stat을 부여)

 

 

 

5. 스프링과의 연계

 

폼 객체와 바인딩

HTML 폼과 폼 객체의 연결은 th:object 속성과 th:field 속성을 사용한다.

  • th:object HTML 폼에 연결되는 폼 객체를 지정하기 위한 속성
  • th:field 입력 항목에 연결되는 폼 객체의 프로퍼티를 지정하기 위한 속성
	<form th:action="@{/sample}" th:method="POST" th:object="${fruit}">
		
		<input type="text" name="fruit" th:field="*{watermelon}" />

	</form>

 

  • th:object  : 연결하고 싶은 폼 객체를 변수 식으로 사용해 지정한다. (변수식에는 모델에 저장한 폼 객체의 속성명을 지정)
  • th:field  : 연결하고 싶은 폼 객체의 프로퍼티를 선택 변수식으로 사용해 지정한다. (선택 변수식은 폼 객체의 프로퍼티명을 지정하며 중첩된 프로퍼티를 지정하는 경우에는 '.'로 프로퍼티명을 연결하면된다. th:field="${fruit.watermelon}" )

 

 

 

입력 오류 표시

스프링 MVC의 입력값 검사 기능에서 발생한 오류 표시에는 th:errors , th:errorclass , #field 객체를 사용한다.

  • th:errors   오류 메시지의 출력 대상을 지정하기 위한 속성
  • th:errorclass 오류 발생 시 적용하는 css 클래스를 지정하기 위한 속성
  • #field 오류 정보에 접근하기 위한 편리한 메서드를 제공하는 객체
<input type="text" name="text" th:field="*{text}" th:errorclass="fieldError"/>
<span th:errors="*{text}">오류메세지</span>