파게로그

Thymeleaf 본문

콤퓨타 왕기초/Spring Boot

Thymeleaf

파게 2021. 5. 5. 12:13

타임리프라고 부르는데 간단한 프로젝트에는 많이 쓰인다고 한다.

 

 

⛳ 공식 사이트

▪ 메인 www.thymeleaf.org

 Thymeleaf 문서 www.thymeleaf.org/documentation.html

Thymeleaf + Spring 문서 www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html

 실습 튜토리얼 itutorial.thymeleaf.org

 

 아래 블로그가 처음에 읽기에는 나쁘지 않았다. 템플릿 엔진의 개념과 종류, JSP보다 Thymeleaf를 권장하는 이유를 간단하게 볼 수 있다.

velog.io/@dsunni/

 

Thymeleaf is a modern server-side Java template engine for both web and standalone environments.

Thymeleaf's main goal is to bring elegant natural templates to your development workflow — HTML that can be correctly displayed in browsers and also work as static prototypes, allowing for stronger collaboration in development teams.

With modules for Spring Framework, a host of integrations with your favourite tools, and the ability to plug in your own functionality, Thymeleaf is ideal for modern-day HTML5 JVM web development — although there is much more it can do.

 

주요한 기능은 다음과 같다.

  • Natural templates
  • Integrations galore

Thymeleaf Standard Dialect 5분 맛보기

www.thymeleaf.org/doc/articles/standarddialect5minutes.html

 

🍦 1. Standard Dialects

 

Thymeleaf는 아주 높은 확장성을 지니며, 템플릿 속성, 그리고 태그까지도 내가 원하는 이름과 함께 내가 원하는 대로 일련의 세트를 정의할 수 있도록 하고, 내가 원하는 문법 내에서 내가 원하는 expression들을 evaluate할 수 있도록 하며, 내가 원하는 로직을 적용할 수 있도록 한다. 즉, 보다 template engine framework와 같은 것이다.

그럼에도 불구하고, 별도의 설치 및 구성 없이, 이는 Standard나 SpringStandard로 불리는 standard dialects로 가능한데 이는 기능의 집합으로서, 대부분의 시나리오에 대해서 충분하거나 넘치는 기능을 갖는다. 템플릿에 이러한 standard dialects가 쓰였을 때에는 바로 식별할 수 있는데, 이들은 <span th:text="...">와 같이 th 접두사로 시작하는 속성을 포함하기 때문이다.

Standard와 SpringStandard dialects는 거의 동일하나, 다만 SpringStandard는 표현의 evaluation을 위해 OGNL(Object-Graph Navigation Language) 대신 Spring Expression Language를 쓰는 것과 같은 Spring MVC 어플리케이션과 통합하기 위한 특정 기능을 포함하고 있다.

또한 여기서 별다른 언급이 없으면 주로 Standard dialects에 대해 언급하는 것이다.

 

 

🍦 2. Standard Expression syntax

 

대개의 Thymeleaf 속성은 그 값을 expression이거나, 또는 expression을 포함하는 것으로 설정하는데, 그 안에 쓰인 dialects 때문에 이를 Standard Expressions라고 부를 것이다. 이들은 아래 5가지의 유형일 수 있다.

 

${. . .} Variable expressions
*{. . .} Selection expressions
#{. . .} Message(i18n) expressions
@{. . .} Link(URL) expressions
~{. . .} Fragment expressions

 

 

2.1. Variable expressions

 

OGNL expression, 또는 Spring과 Thymeleaf를 통합하고 있다면 Spring EL로서 context variable 위에서 실행되며, Spring 용어로는 model attributes라 불린다. 아래와 같이 생겼다.

 

${session.user.name}

 

또한 그것들은 attribute를 이용하여, attribute 값이나 그것의 부분으로서 찾을 수 있다.

 

<span th:text="${book.author.name}">

 

위 표현은 OGNL과 SpringEL 모두에서 다음과 같다.

 

((Book)context.getVariable("book")).getAuthor().getName()

 

하지만 우리는 output만 수반할 뿐 아니라 conditionals, iteration과 같은 보다 복잡한 처리를 수반하는 시나리오에서 다양한 표현을 찾을 수 있다.

 

<li th:each="book : ${books}">

 

여기서 ${books}는 context에서 books라 불리는 변수를 선택하며, th:each 루프에서 사용될 iterable로 evaluate한다.

 

 

2.2. Selection expressions

 

Selection expressions는 Variable expressions와 거의 비슷한데, 다만 모든 context variables map이 아닌 이전에 선택된 객체에 대해서만 실행된다. 아래와 같이 생겼다.

 

*{customer.name}

 

그들의 행위 대상 객체는 th:object 속성에 의해서 구체화된다.

 

<div th:object="${book}">
   <!-- ... -->
   <span th:text="*{title}">...</span>
   <!-- ... -->
</div>

 

이는 다음과 동등하다.

 

{
    final Book selection = (Book) context.getVariable("book"); // th:object="${book}"
    output(selection.getTitle()); // th:text="*{title}"
}

 

 

2.3. Message (i18n) expressions

 

'i18n'은 'internationalization'과 동일한 의미로서 그냥 i랑 n 사이에 18개의 문자가 있어서 저렇게 쓴다고 한다. SW의 국제화에서는 다음과 같은 작업들이 요구된다.

▪ 언어 및 지역에 따른 번역
 운영체제 및 플랫폼에 따른 인코딩
 문자열 치환 방법
 국제화 UI (문자열 크기 변화, 폰트, 아이콘 등)
 쓰기 방향의 차이 (LTR, RTL)
 숫자, 공백, 화폐, 날짜, 주소, 측정 단위 등 표기
 타임존, 썸머 타임 등 시각
 문자열 정렬 방법

 

Message expressions는 종종 text externalization, internationalization or i18n이라 불리는데, 우리가 .properties 파일과 같은 외부 소스로부터 locale-specific한 메시지를 검색하도록 해주며, 이는 그들을 key를 통해 참조하며 수의적으로 일련의 파라미터를 적용하여 참조함으로써 이루어진다.

Spring applications에서는, 아래 코드는 자동적으로 Spring의 MessageSource 매커니즘과 통합할 것이다.

 

#{main.title}
#{message.entrycreated(${entryId})}

 

이들을 아래와 같은 템플릿에서 찾을 수 있다.

 

<table>
  ...
  <th th:text="#{header.address.city}">...</th>
  <th th:text="#{header.address.country}">...</th>
  ...
</table>

 

message key가 context 변수의 값에 의해 결정되기를 원하거나, 다음과 같이 파라미터로 변수를 특정하기를 원한다면, Message expressions 내에 Variable expressions를 사용할 수 있다.

 

#{${config.adminWelcomeKey}(${session.user.name})}

 

 

2.4. Link(URL) expressions

 

Link expressions는 URL을 빌드하고 유용한 context와 세션 정보를 더하도록(URL rewriting이라 불리는 작업) 의도되었다. 따라서 내 웹 서버의 /myapp이라는 context에 배포된 웹 어플리케이션의 경우 expression은 다음과 같다.

 

<a th:href="@{/order/list}">...</a>

 

그리고 위의 표현은 아래와 같이 변환될 수 있다.

 

<a href="/myapp/order/list">...</a>

 

만약 우리가 활성화되지 않은 세션과 쿠키를 유지해야 한다면, 또는 서버가 이를 알지 못한다면 아래와 같이 작성할 수 있다.

 

<a href="/myapp/order/list;jsessionid=23fa31abd41ea093">...</a>

 

또한 URL은 아래와 같이 파라미터를 가질 수 있다.

 

<a th:href="@{/order/details(id=${orderId},type=${orderType})}">...</a>

 

위의 표현은 아래와 같다. &는 &amp;로 escape된 것을 볼 수 있다.

 

<!-- Note ampersands (&) should be HTML-escaped in tag attributes... -->
<a href="/myapp/order/details?id=23&amp;type=online">...</a>

 

Link expressions는 상대적일 수 있는데, URL에 접두사로 붙는 application context가 없는 경우를 말한다.

 

<a th:href="@{../documents/report}">...</a>

 

또한 server-relative일 수 있다(다시 말하지만, 접두사로 붙는 application context가 없다).

 

<a th:href="@{~/contents/main}">...</a>

 

또한 protocol-relative일 수 있다(절대경로 URL처럼, 그러나 브라우저는 표시되는 페이지에서 같은 HTTP나 HTTPS 프로토콜을 사용할 것이다).

 

<a th:href="@{//static.mycompany.com/res/initial}">...</a>

 

물론 다음과 같이 Link expressions는 절대경로일 수 있다.

 

<a th:href="@{http://www.mycompany.com/main}">...</a>

 

하지만 protocol-relative하거나 절대경로 URL에서는, Thymeleaf Link Expression은 어떤 값을 더하나? 쉽다. response filters에 의해 정의된 URL-rewriting의 가능성이다. Servlet 기반의 웹 어플리케이션에서는, context-relative, relative, absolute 등 모든 결과 URL에 대해서 Thymeleaf는 항상 HttpServletResponse.encodeUrl(...) 메커니즘을 호출할 것이고 그 후에 URL을 표시할 것이다. 즉 필터는 어플리케이션을 위한 커스터마이즈된 URL-rewriting을 수행할 수 있다는 것이며, 이는 HttpServletResponse 객체를 wrapping하는 보편적인 매커니즘 덕분이다.

 

 

2.5. Fragment expressions

 

Fragment expressions는 markup의 파편을 표현하고 그것들을 템플릿 주변으로 옮기는 데에 쉬운 방법이다. 이러한 표현 덕분에 파편은 복제될 수 있고, 다른 템플릿에 arguments로 전달될 수 있다.

가장 일반적인 사용법은 th:insert나 th:replace를 이용한 fragment insertion이다.

 

<div th:insert="~{commons :: main}">...</div>

 

하지만 이는 아래와 같이, 다른 변수와 함께 어디에나 사용될 수 있다.

 

<div th:with="frag=~{footer :: #main/text()}">
  <p th:insert="${frag}">
</div>

 

fragment expressions는 arguments를 가질 수 있다.

 

 

2.6. Literals and operations

 

리터럴과 연산자가 잘 구비되어 있다.

 

  • Literals:
    • Text literals: 'one text', 'Another one!',…
    • Number literals: 0, 34, 3.0, 12.3,…
    • Boolean literals: true, false
    • Null literal: null
    • Literal tokens: one, sometext, main,…
  • Text operations:
    • String concatenation: +
    • Literal substitutions: |The name is ${name}|
  • Arithmetic operations:
    • Binary operators: +, -, *, /, %
    • Minus sign (unary operator): -
  • Boolean operations:
    • Binary operators: and, or
    • Boolean negation (unary operator): !, not
  • Comparisons and equality:
    • Comparators: >, <, >=, <= (gt, lt, ge, le)
    • Equality operators: ==, != (eq, ne)
  • Conditional operators:
    • If-then: (if) ? (then)
    • If-then-else: (if) ? (then) : (else)
    • Default: (value) ?: (defaultvalue)

 

 

2.7. Expression preprocessing

 

expression에 대해 알아야 할 마지막 것은, expression preprocessing이라는 것인데, 이는 다음과 같이 __ 사이에 있는 것으로 구분된다.

 

#{selection.__${sel.code}__}

 

처음 실행될 variable expression(${sel.code})이 보이며, 이는 아마 "ALL"이 결과인데, 이는 후에 실행될 real expression의 부분으로 사용될 것이며, 이 경우에는 internationalization one(selection.ALL이라는 키와 있는 메시지를 찾을)이다.

 

 

🍦 3. Some basic attributes

 

Standard Dialect에서 가장 기본적인 속성 중 2개를 살펴보자. th:text로 시작하며, 태그의 body를 대체한다(notice again the prototyping abilities here).

 

<p th:text="#{msg.welcome}">Welcome everyone!</p>

 

표현에 의해 리턴된 배열이나 리스트에 의해 명시된 횟수만큼 element를 반복하는 th:each는, element 반복을 위한 내부 변수를 만드는데, Java의 foreach 표현과 문법적으로 동일하다.

 

<li th:each="book : ${books}" th:text="${book.title}">En las Orillas del Sar</li>

 

마지막으로, Thymeleaf는 단지 자신의 expression을 evaluate하고 속성들의 값을 결과값으로 설정하는 특정 XHTML이나 HTML5 속성을 위한 많은 th 속성을 포함한다. 그들의 이름은 그들이 설정할 값의 속성을 모방한다.

 

<form th:action="@{/createOrder}">

 

<input type="button" th:value="#{form.submit}" />

 

<a th:href="@{/admin/users}">

 

 

🍦 4. Want to know more?

 

"Using Thymeleaf" 튜토리얼을 추천한다.

Comments