2023.12.12 - [SSR(Server Side Rendering)/Thymeleaf] - Thymeleaf[타임리프]란? 타임리프의 기본 기능
Thymeleaf[타임리프]란? 타임리프의 기본 기능
타임리프(Thymeleaf)란? - 타임리프는 백엔드 서버에서 HTML을 동적으로 렌더링 하는 용도로 사용되는 템플릿 엔진이다. ( 백엔드 서버에서 동적으로 렌더링 한다는 말은 타임 리프가 서버 사이드 HTM
junhyuk-develop.tistory.com
타임리프가 무엇이고, 그 특징과 간단한 기본 기능들의 설명을 앞선 글에서 써두었다.
본 게시글을 읽기 전에, 위의 글을 읽고 오는 것을 추천한다.
객체 접근
- HTTP 요청 파라미터 접근 → param
- HTTP 세션 접근 → session
- 스프링 빈 접근 → @
Controller에 아래와 같이 간단히 작성하고 코드로 확인해보자.
@GetMapping("/basic-objects")
public String basicObjects(HttpSession session) {
session.setAttribute("sessionData", "Hello Session");
return "basic/basic-objects";
}
@Component("helloBean")
static class HelloBean {
public String hello(String data) {
return "Hello " + data;
}
/basic-objects로 GET 요청을 할 때, ?paramData= ... 로 파라미터 값을 전달하였다.
<h1>편의 객체</h1>
<ul>
<li>Request Parameter = <span th:text="${param.paramData}"></span></li>
<li>session = <span th:text="${session.sessionData}"></span></li>
<li>spring bean = <span th:text="${@helloBean.hello('Spring!')}"></span></
li>
</ul>
${param.paramData} 를 통해 간단한 HTTP 요청 파라미터에 접근할 수 있다. → getParameter()와 같다고 보면 됨.
${session.sessionData} 를 통해 HTTP 세션에 접근할 수 있다.
${@스프링 빈 이름.메서드()} 를 통해 스프링 빈에 접근하여 타임 리프에서 해당 메서드를 사용할 수 있다.
추가로 기본 객체로 제공하는 locale도 있다.
<li>locale = <span th:text="${#locale}"></span></li>
${#locale} 와 같이 사용하면 타임리프가 제공하는 기본 객체인 locale정보를 사용할 수 있다.
예를 들어, locale이 한국이라면 ko가 출력될 것이다.
타임리프 유틸리티 객체들
- #message : 메시지, 국제화 처리
- #uris : URI 이스케이프 지원
- #dates : java.util.Date 서식 지원
- #calendars : java.util.Calendar 서식 지원
- #temporals : 자바8 날짜 서식 지원
- #numbers : 숫자 서식 지원
- #strings : 문자 관련 편의 기능
- #objects : 객체 관련 기능 제공
- #bools : boolean 관련 기능 제공
- #arrays : 배열 관련 기능 제공
- #lists , #sets , #maps : 컬렉션 관련 기능 제공
- #ids : 아이디 처리 관련 기능 제공, 뒤에서 설명
타임리프 유틸리티 객체들에 대해 자세한 설명 :
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects
Tutorial: Using Thymeleaf
1 Introducing Thymeleaf 1.1 What is Thymeleaf? Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. The main goal of Thymeleaf is to provide a
www.thymeleaf.org
유틸리티 객체 예시
Tutorial: Using Thymeleaf
1 Introducing Thymeleaf 1.1 What is Thymeleaf? Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. The main goal of Thymeleaf is to provide a
www.thymeleaf.org
※ 유틸리티 객체들은 대략 이런 것이 있다 알아두고, 필요할 때 찾아서 사용하면 된다.
자바 날짜 지원 유틸리티 객체
#temporals 를 통해 사용이 가능하다.
EX)
@GetMapping("/date")
public String date(Model model) {
model.addAttribute("localDateTime", LocalDateTime.now());
return "basic/date";
}
<h1>LocalDateTime</h1>
<ul>
<li>default = <span th:text="${localDateTime}"></span></li>
<li>yyyy-MM-dd HH:mm:ss = <span th:text="${#temporals.format(localDateTime, 'yyyy-MM-dd HH:mm:ss')}"></span></li>
</ul>
<h1>LocalDateTime - Utils</h1>
<ul>
<li>${#temporals.day(localDateTime)} = <span th:text="${#temporals.day(localDateTime)}"></span></li>
<li>${#temporals.month(localDateTime)} = <span th:text="${#temporals.month(localDateTime)}"></span></li>
<li>${#temporals.monthName(localDateTime)} = <span th:text="${#temporals.monthName(localDateTime)}"></span></li>
<li>${#temporals.monthNameShort(localDateTime)} = <span th:text="${#temporals.monthNameShort(localDateTime)}"></span></li>
<li>${#temporals.year(localDateTime)} = <span th:text="${#temporals.year(localDateTime)}"></span></li>
<li>${#temporals.dayOfWeek(localDateTime)} = <span th:text="${#temporals.dayOfWeek(localDateTime)}"></span></li>
<li>${#temporals.dayOfWeekName(localDateTime)} = <span th:text="${#temporals.dayOfWeekName(localDateTime)}"></span></li>
<li>${#temporals.dayOfWeekNameShort(localDateTime)} = <span th:text="${#temporals.dayOfWeekNameShort(localDateTime)}"></span></li>
<li>${#temporals.hour(localDateTime)} = <span th:text="${#temporals.hour(localDateTime)}"></span></li>
<li>${#temporals.minute(localDateTime)} = <span th:text="${#temporals.minute(localDateTime)}"></span></li>
<li>${#temporals.second(localDateTime)} = <span th:text="${#temporals.second(localDateTime)}"></span></li>
<li>${#temporals.nanosecond(localDateTime)} = <span th:text="${#temporals.nanosecond(localDateTime)}"></span></li>
</ul>
${#temporals.format( 받은 데이터, '날짜 포멧 형식' )} 를 통해 날짜를 표현할 수 있고, day, month, monthName 등등 개별적으로 많은 정보를 얻을 수 있다.
URL 링크
타임리프에서 URL을 생성할 때는 @{...} 문법을 사용하면 된다.
추가로, 파라미터를 이용해서 링크를 만들 수도 있다.
EX)
@GetMapping("/link")
public String link(Model model) {
model.addAttribute("param1", "data1");
model.addAttribute("param2", "data2");
return "basic/link";
}
<h1>URL 링크</h1>
<ul>
<li><a th:href="@{/hello}">basic url</a></li>
<li><a th:href="@{/hello(param1=${param1}, param2=${param2})}">hello query param</a></li>
<li><a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}">path variable</a></li>
<li><a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}">path variable + query parameter</a></li>
</ul>
처음은 그냥 일반 url을 표현할 때의 경우이다. → @{경로}
두번째는 /hello 로 링크를 연결하되, param1,2 파라미터를 전달했을 때이다. → /hello?param1=...¶m2=...
세번째는 param1,2를 링크로 사용한 경우이다. → /hello/param1/param2
마지막은 param1을 링크로 사용하고 param2를 파라미터로 전달하는 경우이다. → /hello/param1?param2=...
리터럴 (Literals)
리터럴은 소스 코드상에 고정된 값을 말하는 용어이다.
예를 들어, "hello"는 문자 리터럴, 10은 숫자 리터럴이다.
타임리프에서 문자 리터럴은 항상 ' (작은 따옴표)로 감싸야 한다.
하지만, 타임리프에서는 공백 없이 쭉 이어진다면, 하나의 의미 있는 토큰으로 인식하여 작은 따옴표를 생략할 수 있다.
예를 들어, hello가 그 예시이다. → 'hello'가 맞지만 hello로 해도 인식한다는 말이다.
그러나, hello world와 같은 문장은 예시가 되지 않는다. 공백을 포함하기 때문이다.
때문에 'hello world' 가 되어야 한다.
이 불편한 리터럴을 해결해주는 문법이 있는데, 그것이 리터럴 대체(Literal substitutions) 문법 이다.
<li>리터럴 대체 |hello ${data}| = <span th:text="|hello ${data}|"></span></li>
이와 같이, | ... | 와 같은 형식으로 사용하면 된다.
연산
타임리프는 자바와 같이 간단한 연산을 제공한다.
그러나, HTML안에서 사용하기 때문에 HTML 엔티티를 사용하는 부분만 주의하자!
EX)
<ul>
<li>산술 연산
<ul>
<li>10 + 2 = <span th:text="10 + 2"></span></li>
<li>10 % 2 == 0 = <span th:text="10 % 2 == 0"></span></li>
</ul>
</li>
<li>비교 연산
<ul>
<li>1 > 10 = <span th:text="1 > 10"></span></li>
<li>1 gt 10 = <span th:text="1 gt 10"></span></li>
<li>1 >= 10 = <span th:text="1 >= 10"></span></li>
<li>1 ge 10 = <span th:text="1 ge 10"></span></li>
<li>1 == 10 = <span th:text="1 == 10"></span></li>
<li>1 != 10 = <span th:text="1 != 10"></span></li>
</ul>
</li>
<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>
</ul>
- 비교연산: HTML 엔티티를 사용해야 하는 부분을 주의하자, > (gt), < (lt), >= (ge), <= (le), ! (not), == (eq), != (neq, ne)
- 조건식: 자바의 조건식과 유사하다.
- Elvis 연산자: 조건식의 편의 버전
- No-Operation: _ 인 경우 마치 타임리프가 실행되지 않는 것 처럼 동작한다. 이것을 잘 사용하면 HTML 의 내용 그대로 활용할 수 있다. 마지막 예를 보면 데이터가 없습니다. 부분이 그대로 출력된다.
- ${data}에서 data가 있으면 그 데이터를 출력하고 만약 null이라면 타임리프가 없는 것처럼 기본 html의 내용 실행
속성 값 설정
타임리프는 주로 HTML 태그에 th:* 속성을 지정하는 방식으로 동작한다.
th:* 로 속성을 적용하면 기존 속성을 대체한다. 기존 속성이 없으면 새로 만든다.
<h1>속성 설정</h1>
<input type="text" name="mock" th:name="userA" />
<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/>
속성 설정을 보면, name 부분이 타임리프 렌더링이 되면,
<input type="text" name="userA" />
으로 표현된다.
속성 추가
- th:attrappend : 속성 값의 뒤에 값을 추가한다. → 결과 : text large
- th:attrprepend : 속성 값의 앞에 값을 추가한다. → 결과 : large text
- th:classappend : class 속성에 자연스럽게 추가한다. → 결과 : large text
이는, 실무에서는 거의 안쓰이고 th:classappend 정도만 가끔 사용된다고 한다.
checked 처리
HTML에서는 checked 속성이 있기만 하면, true, false와 상관 없이 checked 처리가 되어버린다.
이를 해결하기 위해, 타임리프의 th:checked 는 값이 false 인 경우 checked 속성 자체를 제거한다.
<input type="checkbox" name="active" th:checked="false" />
-> 타임리프 렌더링 후: <input type="checkbox" name="active" />
반복
자바와 같이 타임리프도 반복문을 제공한다.
th:each 를 사용해서 반복을 사용할 수 있다.
Ex)
<tr th:each="user : ${users}">
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
반복시 오른쪽 컬렉션( ${users} )의 값을 하나씩 꺼내서 왼쪽 변수( user )에 담아서 태그를 반복 실행
타임리프는 추가로 반복에서 사용할 수 있는 여러 상태 값을 지원한다.
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">username</td>
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
<td>
index = <span th:text="${userStat.index}"></span>
count = <span th:text="${userStat.count}"></span>
size = <span th:text="${userStat.size}"></span>
even? = <span th:text="${userStat.even}"></span>
odd? = <span th:text="${userStat.odd}"></span>
first? = <span th:text="${userStat.first}"></span>
last? = <span th:text="${userStat.last}"></span>
current = <span th:text="${userStat.current}"></span>
</td>
</tr>
위에서 말한 th:each문을 사용하되, 이번에는 userStat가 더 있다.
이를 설정해서 반복의 상태를 확인 할 수 있다. 이는 생략이 가능하다.
만약, 생략하게 된다면 지정한 변수명(user) + Stat가 기본 이름이 된다.
여기서는 user + Stat = userStat이므로 생략이 가능하다.
- index : 0부터 시작하는 값
- count : 1부터 시작하는 값
- size : 전체 사이즈
- even , odd : 홀수, 짝수 여부( boolean형태로 )
- first , last :처음, 마지막 여부( boolean형태로 )
- current : 현재 객체
※count or 홀,짝 확인 or 처음,마지막 여부 등은 사용할만 하다.
조건식 - 조건부 평가
타임리프의 조건식
- if
- unless ( if 의 반대)
- switch
Ex)
<span th:text="'미성년자'" th:if="${user.age lt 20}"></span>
<span th:text="'미성년자'" th:unless="${user.age ge 20}"></span>
th:if 문의 조건이 true라면 출력되고, 아니라면 태그 자체를 렌더링하지 않는다.
th:unless 문도 마찬가지로 조건이 맞아야 출력하고, 아니라면 렌더링을 하지 않는다.
unless는 if의 반대이기 때문에 조건식이 성립되지 않아야 true이다.
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">1</td>
<td th:text="${user.username}">username</td>
<td th:switch="${user.age}">
<span th:case="10">10살</span>
<span th:case="20">20살</span>
<span th:case="*">기타</span>
</td>
</tr>
th:switch는 자바에서 사용하는 switch와 동일하다.
th:case를 사용하고, * 은 만족하는 조건이 없을 때 사용하는 Default 값이다.
다음 게시글
분량을 나눠야해서 이번 게시글은 여기까지..
다음 게시글에는 타임리프만의 주석 표현식, 블록 형식, 자바스크립트 인라인, 템플릿 조각을 활용하는 방식 등을 설명하겠다.
'SSR(Server Side Rendering) > Thymeleaf' 카테고리의 다른 글
Thymeleaf와 Spring Form(체크 박스, 라디오 버튼, 셀렉트 박스) (0) | 2023.12.13 |
---|---|
Thymeleaf(타임리프) 기능(주석, 블록, 자바스크립트 인라인, 템플릿 조각, 템플릿 레이아웃) (0) | 2023.12.12 |
Thymeleaf[타임리프]란? 타임리프의 기본 기능(표현식, escape, 스프링EL, 변수 선언) (0) | 2023.12.12 |