◦ 변수 표현식: ${...}
◦ 선택 변수 표현식: *{...}
◦ 메시지 표현식: #{...}
◦ 링크 URL 표현식: @{...}
◦ 조각 표현식: ~{...}
리터럴
- 텍스트: 'one text', 'Another one!',…
- 숫자: 0, 34, 3.0, 12.3,…
- 불린: true, false
- 널: null
- 리터럴 토큰: one, sometext, main,…
문자 연산:
- 문자 합치기: +
- 리터럴 대체: |The name is ${name}|
산술 연산:
- Binary operators: +, -, *, /, %
- Minus sign (unary operator): -
불린 연산:
- Binary operators: and, or
- Boolean negation (unary operator): !, not
비교와 동등:
- 비교: >, <, >=, <= (gt, lt, ge, le)
- 동등 연산: ==, != (eq, ne)
조건 연산:
- If-then: (if) ? (then)
- If-then-else: (if) ? (then) : (else)
- Default: (value) ?: (defaultvalue)
특별한 토큰:
- No-Operation: _
<html xmlns:th="[http://www.thymeleaf.org](http://www.thymeleaf.org/)">
-> 타임리프 사용 시 항상 적어줘야 함.
text
기본 텍스트 출력
<span th: text=&{data}">
[[${data}]]
utext
th:text -> th:utext
[[...]] -> [(...)]
text 내용을 작성할 때 <b>와 같은 태그들을 넣어 text를 진하게 하려고 한다.
하지만 출력을 보면 강조되지 않고 <b>태그가 그대로 출력되는 것을 볼 수 있다.
웹 브라우저에서 < 는 태그의 시작이므로 문자로 인식하지 않기 때문에 방법이 필요.(< → <
, > → >
)
기본적으로 타임리프는 escape(특수 문자를 HTML 엔티티로 변경하는 것)를 제공하므로 그대로 사용하기 위해 utext를 사용해줘야 한다.
@Data
class User{
private String username;
private int age;
}
타임리프에서 User 객체의 필드를 접근할 때 세 가지 방법으로 접근할 수 있다.
${user.username}
${user['username']}
${user.getUsername()}
타임리프가 제공하는 기본 객체들을 사용할 수 있다.
${param.paramData}
: session과 model에 담아준 정보들을 다음과 같이 출력할 수 있다. 또한 @RequestParameter와 같이 많이 쓰이는 것들은 param.(이름) 으로 바로 접근 가능하다.${session.sessionData}
: session에 넣어준 sessionData인 Hello Session이 출력되는 것을 볼 수 있다.${@helloBean.hello('Spring!')}
: 우리가 스프링 빈으로 등록한 helloBean을 바로 접근할 수 있다.
다음과 같이 LocalDateTime.now()
를 활용하여 현재 시간에 대한 정보를 얻을 수 있다.
<span th:text="${#temporals.day(localDateTime)}"></span></li>
<span th:text="${#temporals.month(localDateTime)}"></span>
타임리프에서 URL을 생성할 때는 @{...}
사용
<a th:href="@{/hello}">
<a th:href="@{/hello(param1=${param1}, param2=${param2})}">
<a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}">
<a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}">
리터럴 : 소스 코드상 고정된 값
ex)
String a = “Hello
int a = 10 * 20
타임리프에서 문자 리터럴은 항상 ‘(작은 따옴표)'로 감싸야 한다.
<span th:text=”’hello’”>
문자를 항상 ‘로 감싸는 것은 귀찮으니 공백없이 쭉 이어지면 하나의 토큰으로 인식해 따옴표를 생략 가능하다.
ex) A-Z , a-z , 0-9 , [] , . , - , _
리터럴 표현하는 4가지 방식
“’hello’ + ‘ world!”
“’hello world!’”
“’hello ‘ + ${data}”
“|hello ${data}|”
→ 마지막 문법처럼 || 안에 내용을 작성하면 문자 그대로 출력 가능하다.
<li>조건식
<ul>
<li>(10 % 2 == 0)? '짝수':'홀수' = <span th:text="(10 % 2 == 0)? '짝수':'홀수'"></span></li>
</ul>
</li>
<li>Elvis 연산자
<ul>
<li>${data}?: '데이터가 없습니다.' = <span th:text="${data}?: '데이터가 없습니다.'"></span></li>
<li>${nullData}?: '데이터가 없습니다.' = <span th:text="${nullData}?: '데이터가 없습니다.'"></span></li>
</ul>
</li>
<li>No-Operation
<ul>
<li>${data}?: _ = <span th:text="${data}?: _">데이터가 없습니다.</span></li>
<li>${nullData}?: _ = <span th:text="${nullData}?: _">데이터가 없습니다.</span></li>
</ul>
</li>
_
(조건에 만족하지 않을 때)인경우 타임리프가 실행되지 않는 것 처럼 동작 → th:text="${nullData}?: _”
이 부분이 없는 것과 같다타임리프 태그 속성(Attribute)
타임리프는 HTML 태그에 th:*
속성을 지정하는 방식으로 동작한다.
th:*
속성을 적용하면 기존 속성을 대체하고 없으면 새로 만든다.
<h1>속성 추가</h1>
- th:attrappend = <input type="text" class="text" th:attrappend="class=' large'" /><br/>
- th:attrprepend = <input type="text" class="text" th:attrprepend="class='large '" /><br/>
- th:classappend = <input type="text" class="text" th:classappend="large"/><br/>
<h1>checked 처리</h1>
- checked o <input type="checkbox" name="active" th:checked="true" /><br/>
- checked x <input type="checkbox" name="active" th:checked="false" /><br/>
- checked=false <input type="checkbox" name="active" checked="false" /><br/>
th:attrapend
, th:attrprepend
, th:classappend
모두 기존 class에 추가하여 새로운 class를 만든다true -> checked
, false → 속성 값 삭제
해준다.th:each
를 활용하여 코드 반복을 할 수 있다.
<tr th:each="user : ${users}">
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
if
: 만족하면
unless
: 만족하지 않으면
<td>
<span th:text="${user.age}">0</span>
<span th:text="'미성년자'" th:if="${user.age lt 20}"></span>
<span th:text="'미성년자'" th:unless="${user.age ge 20}"></span>
</td>
th:if=”${user.age lt 20}”
: 나이가 20 미만이면 출력
th:unless=”${user.age ge 20}”
: 나이가 20 이상이 아니면 출력
자바스크립트 표준 HTML 주석은 타임리프가 렌더링하지 않고 그대로 남겨둔다.
<!--
<span th:text="${data}">html data</span>
-->
타임리프의 진짜 주석으로 렌더링에서 주석 부분 제거
<!--/* [[${data}]] */-->
or
<!--/*-->
<span th:text="${data}">html data</span>
<!--*/-->
HTML파일을 그대로 열면 주석처리가 되고, 타임리프 렌더링 한 경우에만 보인다.
<!--/*/
<span th:text="${data}">html data</span>
/*/-->
<th:block>
: HTML 태그가 아닌 타임리프의 유일한 자체 태그
<th:block th:each="user : ${users}">
<div>
사용자 이름1 <span th:text="${user.username}"></span>
사용자 나이1 <span th:text="${user.age}"></span>
</div>
<div>
요약 <span th:text="${user.username} + ' / ' + ${user.age}"></span>
</div>
</th:block>
반복문을 이용하여 <div> 를 각각 출력하는 것과 같이 애매한 상황에서 사용
자바스크립트를 사용할 때는 th:inline
속성을 넣어줘야 한다.
<script th:inline=”javascript”>
var username = [[${user.username}]];
인라인 사용 전 → var username = userA;
인라인 사용 후 → var username = "userA";
var username2 = /*[[${user.username}]]*/ “test username”;
인라인 사용 전 → var username2 = /*userA*/ "test username";
인라인 사용 후 → `var username2 = "*userA";*
(인라인 사용 후 결과를 보면 주석 부분이 제거되고 기대한 “userA”가 정확하게 적용)
var user = [[${user}]];
인라인 사용 전 → var user = BasicController.User(username=userA, age=10);
인라인 사용 후 → var user = {"username":"userA","age":10};
(인라인 사용 후 객체를 JSON으로 변환)
웹 페이지의 공통 영역들을 중복해서 사용하는 것은 비효율적이다.
따라서 템플릿을 사용하면 공통 영역들을 한번에 관리할 수 있다.
<footer th:fragment="copy">
푸터 자리 입니다.
</footer>
template/fragment/footer :: copy
: template/fragment/footer.html 템플릿에 있는
th:fragment="copy" 라는 부분을 템플릿 조각으로 가져와서 사용한다는 의미이다
부분 포함 insert : th:insert
는 현재 태그 내부에 추가
<div th:insert="~{template/fragment/footer :: copy}"></div>
부분 포함 replace : th:replace
는 현재 태그( div )를 대체한다.
<div th:replace="~{template/fragment/footer :: copy}"></div>
파라미터 사용 : 파라미터를 넘겨 동적으로 조각을 렌더링할 수 있다.
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>
템플릿 조각은 일부 코드 조각을 가져와 사용했다면 템플릿 레이아웃은 코드 조각을 레이아웃에 넘겨서 사용하는 방법이다.
메인 레이아웃이 있고 거기에 필요한 코드 조각을 전달해 View를 완성한다.
head
<head th:replace="template/layout/base :: common_header(~{::title},~{::link})">
<title>메인 타이틀</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>
common_header(~{::title},~{::link})
이 부분에 각각 title과 link가 전달된다.
그리고 메인 레이아웃인 template/layout/base
에 전달되어 title과 link가 렌더링된 head로 교체된다.
html
<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title}, ~{::section})}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>메인 페이지 타이틀</title>
</head>
<body>
<section>
<p>메인 페이지 컨텐츠</p>
<div>메인 페이지 포함 내용</div>
</section>
</body>
</html>
head와 달리 html 전체 페이지를 교체하는 방법이다.
template/layoutExtend/layoutFile
<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
title과 section에 내용을 template/layoutExtend/layoutFile
에 전달하여 렌더링된 html로 교체된다.
이 때 템플릿 레이아웃은 th:fragment
로 표현한다.