공식 사이트: https://www.thymeleaf.org/
공식 메뉴얼 - 기본 기능: https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
공식 메뉴얼 - 스프링 통합: https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html
<html xmls:th="https://thymeleaf.org">
간단한 표현
변수 표현식: ${...}
선택 변수 표현식: *{...}
메시지 표현식: #{...}
링크 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: _
text / utext
th:text / [[...]]
기본적인 텍스 출력 방법
<span th:text="${data}">여기 텍스트가 data로 대체</span>
<span>[[$data]]</span>
th:utext / [{...}]
Escape기능(HTML엔티티로 변경하는 기능)을 의도적으로 사용하지
않을 때 사용
<span th:utext="${data}">여기 텍스트가 data로 대체</span>
<span>[{$data}]</spna>
변수 SpringEL
${...}
Object (모델객체명 : user)
<span th:text="${user.username}">여기에 대체</span>
<span th:text="${user.['username']}">여기에 대체</span>
<span th:text="${user.getUsername()}">여기에 대체</span>
List (모델객체명 : users)
<span th:text="${users[0].username}">여기에 대체</span>
<span th:text="${users[0].['username']}">여기에 대체</span>
<span th:text="${users[0].getUsername()}">여기에 대체</span>
Map (모델객체명 : userMap)
<span th:text="${userMap.username}">여기에 대체</span>
<span th:text="${userMap.['username']}">여기에 대체</span>
<span th:text="${userMap.getUsername()}">여기에 대체</span>
지역변수
th:with
지역변수를 선언하여 지역변수 선언언한 태그 안에서만 사용
<div th:with="local=${users[0]">
<p>리스트 첫번째 유저명은 <span th:text="$local.username}"></span></p>
</div>
기본객체들
${#request}
${#response}
${#session}
${#servletContext}
${#locale}
URL 링크
@{...}
${param1} = data1 / ${param2} = data2
단순URL
@{/hello}
결과 => /hello
쿼리 파라미터
@{/hello(param1=${param1}, param2=${param2})}
결과 => /hello?param1=data1¶m2=data2
경로변수
@{/hello/{param1}/{param}(param1=${param1}, param2=${param2})}
결과 => /hello/data1/data2
경로변수 + 쿼리 파라미터
@{/hello/{param1}(param1=${param1}, param2=${param2})}
결과 => /hello/data1?param2=data2
리터럴
문자/숫자/불리언(boolean)/널(null)이 존재 하는데
해당 리터럴은 '리터럴'(작은따음표)로 감싸야한다.
" A~Z / a~z / 0~9 / [] / . / _ / - / " 해당 항목들은
하나의 의미있는 토큰으로 인지하여 생략이 가능
<span th:text="hello world!"></span>
-> 오류 공백이 있어 하나의 토큰으로 간주되지 않음
<span th:text="'hello world!'"></span>
-> '(작은 따음표 사용하여 처리)
<span th:text="|hello world!|"></span>
-> | 사용하여 리터럴 대체
연산
Java의 연산과 비슷함
HTML엔티티 사용하는 부분만 확인
비교연산
> : (gt)
< : (lt)
>= : (ge)
<= : (le)
! : (not)
== : (eq)
!= : (neq,ne)
No-Operation : _ (언더바) 사용시 타임리프가 실행되지 않는 것 처럼 동작
속성 값 설정
th:*
속성을 적용하면 기존의 속성을 대체
속성 설정
<input type="text" name="html" th:name="thymeleaf" />
결과 => 해당 name은 thymeleaf로 처리
속성 추가
<input type="text" class="html" th:attrappend="class=' back'" />
결과 => 해당 attrappend 사용시 class는 'html back'로 처리
<input type="text" class="html" th:attrprepend="class='front '" />
결과 => 해당 attrprepend 사용시 class는 'front html'로 처리
<input type="text" class="html" th:classappend="replace" />
결과 => 해당 classappend 사용시 class는 'replace'로 처리
checked 처리
<input type="checkbox" name="active" checked="false" />
=> html에서는 이경우에도 속성에 checked가 존재하여 check처리가 된다.
<input type="checkbox" name="active" th:checked="false" />
=> thymeleaf 사용시 th:checked="false" 인 경우 checked 속성을 제거한다.
반복
th:each
반복기능
<tr th:each="user : ${users}">
<td th:text="${user.username}">유저명</td>
<td th:text="${user.age}">나이</td>
</tr>
th:each 는 List,배열,java.util.Iterable,java.util.Enumeration,Map에서 사용가능
Map은 변수에 담기는 값은 Map.Entry이다
반복상태
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">1번부터시작</td>
<td th:text="${userStat.index}">0번부터 시작</td>
<td th:text="${userStat.size}">전체사이즈</td>
<td th:text="${userStat.even}">홀수여부(true/false)</td>
<td th:text="${userStat.odd}">짝수여부(true/false)</td>
<td th:text="${userStat.first}">처음여부(true/false)</td>
<td th:text="${userStat.last}">마지막여부(true/false)</td>
<td th:text="${userStat.current}">현재객체</td>
</tr>
조건식
if / unless (if의 반대)
age : 10 일때
<span th:text="'미성년자'" th:if="${user.age lt 20}"></span>
결과 => lt 는 '<' 이므로 10 < 20 true 미성년자 출력
<span th:text="'미성년자'" th:if="${user.age lt 20}"></span>
결과 => ge 는 '>=' 이므로 10 >= 20 false 이므로 아무것도 출력안함
<span th:text="'미성년자'" th:unless="${user.age lt 20}"></span>
결과 => ge 는 '>=' 이므로 10 >= 20 false 인데
unless는 if의 반대이므로 true로 미성년자 출력
switch
age : 10일때
<td th:switch="${user.age}">
<span th:case="10">10살</span>
<span th:case="20">20살</spna>
<span th:case="*">기타</span>
</td>
결과 => age가 10이기에 10살이 출력
*은 만족하는 조건이 없을 때 사용하는 디폴트 값
주석
1.html 표준 주석 <!-- -->
자바스크립트의 표준 html주석은 렌더링 하지 않고 남겨둔다.
2.타임리프 주석 <!--/* */-->
타임리프 파서 주석은 타임리프의 진짜 주석으로 렌더링시 주석부분을 제거
3.타임리프 프로토타입 주석 <!--/*/ /*/-->
타임리프를 거치지 않으면 html주석이므로 html표준 주석과 동일하게 작동
타임리프 렌더링시 해당 내용이 출력된다.
블록
<th:block>
<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>
반복문을 블록단위로 묶어 출력시 사용
자바스크립트 인라인
<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";
var user = [[${user}]];
사용전 결과-> var user = class명.User(~~~~);
사용후 결과-> var user = {"username":"userA","age":10};
사용전 : toString()이 호출된 값 / 사용후 : 객체를 JSON으로 변환
-자바스크립트 인라인 each (반복)<script th:inline="javascript">
[# th:each="user, stat : ${users}"]
var user [[${stat.count}]] = [[${user}]];
[/]
</script>
템플릿 조각
웹페이지 개발시 공통영역에 함께 사용하는 영역을 보다 편리하게 지원
<footer th:fragment="copy">
푸터자리
</footer>
<footer th:fragment="copyParam(param1, param2)">
<p th:text="${param1}"></p>
<p th:text="${param2}"></p>
<div th:insert="~{푸터경로/fragment/footer :: copy}"></dvi>
부분포함 replace<div th:replace="~{푸터경로/fragment/footer :: copy}"></div>
부분포함 단순 표현식<div th:replace="푸터경로/fragment/footer :: copy"></div>
파라미터사용<div th:replace="~{푸터경로/fragment/footer :: copyParam('데이터1','데이터2')}"></div>
템플릿 레이아웃
head, css, javascript등 공통 정보를 한 곳에 사용하고,
각 페이지마다 추가 정보를 추가시 사용
공통head (base.html)
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="common_header(title,links)">
<title th:replace="${title}">레이아웃 타이틀</title>
<!-- 공통 -->
공통헤더들
<!-- 추가 -->
<th:block th:replace="${links}" />
</head>
공통헤더 사용
<html xmlns:th="https://www.thymeleaf.org">
<head th:replace="공통헤더경로/base :: common_header(~{::title},~{::link})">
<title>메인타이틀</title>
<!-- 추가 헤더 -->
<link rel="stylesheet" th:href="@{/css/bootstrap.main.css}">
</head>
<bodt>
메인컨텐츠
</body>
</html>
결과 => 공통헤더와 추가헤더가 추가되어 적용
메인타이틀이 전달한 부분으로 교체 ::{link},~{::link}는 현재 페이지의
해당태그를 전달
공통html (layoutFile)
<html th:fragment="layout(title,content)" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:replace="${title}">레이아웃 타이틀</title>
</head>
<body>
<h1>레이아웃</h1>
<div th:replace="${content}">
<p>레이아웃 콘텐츠</p>
</div>
<footer>
레이아웃푸터
</footer>
</body>
</html>
공통html사용
<html th:replace="~{공통html경로/layoutFile :: layout(~{::title},~{::section})}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>메인 타이틀</title>
</haed>
<body>
<section>
<p>메인 컨텐츠</p>
</div> 메인 내용</div>
</section>
</body>
</html>
결과
<html>
<head>
<title>메인 타이틀</title>
<body>
<h1>레이아웃</h1>
<section>
<p>메인 컨텐츠</p>
<div>메인 내용 </div>
</section>
<footer>
레이아웃 푸터
</footer>
</body>
</html>
=> 공통html에 th:fragment속성이 정의되어 있다
해당 레이앗울 기본으로 하고 여기에 필요한 내용을 전달해서 부분변경
=>공통사용html은 현재페이지 section태그를 공통html에 content로 넘겨 사용