데이터를 미리 정의된 템플릿에 바인딩해서 뷰의 출력을 도와주는 것이다.
이렇게 책에서는 나와있는데 사용자에게 보여줄 내용을 처리 결과 데이터를 가지고 HTML 생성해서 클라이언트에 응답을 돌려주는 역할을 한다.
Thymeleaf 는 HTML, XML, JavaScript, CSS 및 텍스트를 처리하고 생성하기 위한 Java 템플릿 엔진입니다.
이 튜토리얼에서는 Spring MVC 애플리케이션의 뷰 레이어에서 몇 가지 기본 사용 사례와 함께 Thymeleaf를 Spring과 함께 사용하는 방법에 대해 설명합니다 .
src/main/resources/templates
폴더 아래에 요청 핸들러 메서드의 반환값 + .html파일
이 참조된다.그래서 웬만하면 스프링 진영에서는 타임리프를 사용하라고 권장한다.
Model addAttribute(String name, Object value)
타임리프를 사용하는 방법에는 여러가지가 있다. 하나씩 알아보자.
<h1 th:text="Hello World">표시하는 부분</h1>
이런 경우처럼 그냥 "" 안에 값을 넣어서 표시할 수도 있고 타임리프의 독자적인 문법인 ${}
를 사용하여 안에 아까 핸들러 메서드에서 넘어온 model같은 값을 넣어서 사용할 수 있다.
<h1>안녕하세요! [[${name}]]</h1>
이런 식으로 사용하여 태그에 속성을 추가하지 않고 본문에 변수를 포함시킬 수 있다.
<h1 th:text="'오늘의 날씨는 ' + '맑음' ">ㅇ</h1>
+를 사용하여 값을 결합할 수 있고
<h1 th:text="|오늘의 날씨는 ${status}| ">ㅇ</h1>
이런식으로 리터럴 치환을 통해 기술할 수 있다.
<div th:with="a=1, b=2">
<span th:text="|${a} + ${b} = ${a+b}|"></span>
</div>
이런식으로 선언할 수 있으며 정의된 태그 내부에서만 사용이 가능하다.
우리가 알고있는 여러가지 비교 등가 연산자를 사용할 수 있다.
<span th:text="1 < 10"></span>
이런식으로 말이다. 문자열 비교도 심지어 가능하다.
<p th:text = "${name} == 길동 ? '길동입니다.' : '길동이가 아닙니다.'"></p>
<div th:if="${name}=='길동'">
<p>길동입니다.</p>
</div>
<div th:unless="${name}=='길동'">
<p>길동이 아닙니다.</p>
</div>
if는 true일 경우 아래의 태그를 실행, unless면 false일때 실행을 한다. 제일 첫 번째의 코드는 삼항 연산자도 사용이 가능하다는 것을 보여준 것이다.
<div th:switch="${name}">
<p th:case="길동" th:text="|${name}입니다.|"></p>
.
.
.
.
.
.
<p th:case="*">명부에 없는 사람입니다.</p>
</div>
이런식으로 switch case문 사용도 가능하다. case가 *인경우는 어떤 값에도 일치하지 않는 경우를 의미한다.
<p th:text="${mb.id}"></p>
<p th:text="${mb.name}"></p>
<p th:text="${mb['id']}"></p>
<p th:text="${mb.['name']}"></p>
이런 방식으로도 접근이 되고 public 접근 제한자의 getter메서드를 참조해서 값을 가져온다.
<div th:object="${mb}">
<p th:text="*{id}"></p>
<p th:text="*{name}"></p>
<p th:text="*{['id']}"></p>
<p th:text="*{['name']}"></p>
</div>
<p th:text="*{list[0]}"></p>
<p th:text="*{list[1]}"></p>
<p th:text="*{list[2]}"></p>
<p th:text="*{list[3]}"></p>
list는 index의 형태로 접근이 가능하다.
<p th:text="${map.kim.name}"></p>
<p th:text="${map.lee.name}"></p>
<p th:text="${map['kim']['name']}"></p>
<p th:text="${map['lee']['name']}"></p>
map.key 형식으로도 참조할 수 있고, map['키'] 와 같이 대괄호를 사용해 참조할 수 있다.
<div th:each="member : ${members}">
<p>[[${member.id}]] : [[${member.name}]]</p>
</div>
th:each="요소 저장 변수 : ${[반복 처리하는 객체]}"
로 반복 처리할 수 있다.
<div th:each="member, s : ${members}" th:object="${member}">
<p>
index -> [[${s.index}]], count-> [[${s.count}]],
size -> [[${s.size}]], current-> [[${s.current}]],
even -> [[${s.even}]], odd -> [[${s.odd}]],
first -> [[${s.first}]], last -> [[${s.last}]],
[[*{id}]] : [[*{name}]]
</p>
</div>
th:each="요소 저장 변수, 상태변수 : ${[반복 처리하는 객체]}"
로 반복 상태도 처리할 수 있다.
상태 변수 | 기능 개요 |
---|---|
index | 0부터 시작하는 인덱스, 현재 인덱스를 표시한다. |
count | 1부터 시작하는 인덱스, 현재 인덱스를 표시한다. |
size | 반복 처리하는 객체의 사이즈를 표시한다. |
current | 현재 반복 요소의 객체를 표시한다. |
even | 현재 요소가 짝수 번째인지 여부를 결정한다. 짝수는 true, 짝수가 아니면 false를 표시한다. |
odd | 현재 요소가 홀수 번째인지 여부 결정한다. 홀수이면 true, 홀수가 아니면 false를 표시한다. |
first | 현재 요소가 첫 번째 요소인지 여부를 결정한다. 첫 번째이면 true, 첫 번째가 아니면 false |
last | 현재 요소가 마지막인지 여부를 결정한다. 마지막이면 true, 마지막이 아니면 false를 표시한다. |
타임리프에서는 자주 사용되는 클래스를 이라는 상수로 정의하고 있어서 그대로 변수 표현식에서 사용할 수 있다.
데이터를 출력할 때 자주 이용하는 것이 '수치', '일시', '문자열'의 포맷 변환입니다.
유틸리티 객체 | 기능 개요 |
---|---|
#strings | 문자 관련 편의 기능 |
#numbers | 숫자 서식 지원 |
#bools | 불리언(Boolean)관련 기능 |
#dates | java.util.Date 서식 지원 |
#objects | 객체 관련 기능 |
#arrays | 배열 관련 기능 |
#lists | List 관련 기능 |
프래그먼트란 단편이라는 의미이다. 다른 템플릿을 삽입하는 것이 유용할 경우가 많다. 왜냐하면 공통된 부분을 계속해서 중복적으로 코드로 작성해야하는 문제가 일어나기 때문에 만약 공통적인 부분이
있다면 그런 것들은 따로 템플릿 파일을 만들어놓고 불러오면 되기 때문이다. 그래서 이런 것들을 fragment
라고도 부른다.
<!-- 18: 프래그먼트를 정의-->
<span th:fragment="one">하나</span>
<span th:fragment="two">둘</span>
<span th:fragment="three">셋</span>
<!-- 18: 프래그먼트 사용하기-->
<h1>Fragment를 아래에 삽입하기</h1>
<div id="one" th:insert="fragment :: one"></div>
<div id="three" th:replace="fragment :: three"></div>
이런식으로 만들어놓고 나중에 가져다가 사용하면 된다.
이렇게 여러 템플릿에서 같은 디자인 레이아웃을 사용하는 경우 공통 레이아웃을 만들고 공유하는 것을 레이아웃화
라고 말한다.
이것을 사용하기 위해서는 레이아웃 전용 라이브러리인 thymeleaf layout dialect
를 이용해야한다.
결국 요약하면 아래 그림과 같이 동작하게 되는 것이다.