SSR(Server Side Rendering)/Thymeleaf

Thymeleaf(타임리프) 기본 기능 및 객체, 문법(리터럴 대체, 반복, 조건)

녁이 2023. 12. 12. 17:48
728x90
반응형

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

 

유틸리티 객체 예시

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-b-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

 

※ 유틸리티 객체들은 대략 이런 것이 있다 알아두고, 필요할 때 찾아서 사용하면 된다.

 

자바 날짜 지원 유틸리티 객체

#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=...&param2=...

세번째는 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 &gt; 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 값이다.

 


다음 게시글

분량을 나눠야해서 이번 게시글은 여기까지..

다음 게시글에는 타임리프만의 주석 표현식, 블록 형식, 자바스크립트 인라인, 템플릿 조각을 활용하는 방식 등을 설명하겠다. 

728x90
반응형