소소한개발팁
article thumbnail
반응형

Thymeleaf 란 ? 

Thymeleaf는 서버 측 Java 템플릿 엔진으로, 웹 애플리케이션에서 동적인 HTML, XML, 또는 다른 템플릿 문서를 생성하는 데 사용됩니다. Thymeleaf는 Spring 프레임워크와 자주 함께 사용되며, 템플릿에서 Java 코드를 인식하여 템플릿 엔진이 HTML을 생성하는 데 도움을 줍니다.

 

th:text, th:utext

th:text : th:text 속성은 Thymeleaf에서 사용되며, 텍스트를 출력할 때 사용됩니다. 이 속성을 사용하면 템플릿에서 서버 측 데이터를 화면에 렌더링할 수 있습니다. 예를 들어, 다음은 Thymeleaf를 사용하여 변수 값을 HTML 페이지에 출력하는 예제입니다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Thymeleaf Example</title>
</head>
<body>
    <h1 th:text="${message}"></h1>
</body>
</html>

이 템플릿에서 ${message}는 서버 측에서 전달된 message 변수의 값을 출력합니다. 즉, th:text 속성을 통해 서버에서 받은 데이터를 동적으로 페이지에 표시할 수 있습니다.

th:utext : th:utext 속성은 th:text와 비슷하지만, 텍스트 내에 HTML 코드를 렌더링할 때 사용됩니다. 이 속성을 사용하면 HTML 태그를 템플릿에서 동적으로 생성하거나, 서버 측에서 받은 HTML을 안전하게 출력할 수 있습니다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Thymeleaf Example</title>
</head>
<body>
    <p th:utext="${htmlContent}"></p>
</body>
</html>

${htmlContent} 변수에는 HTML 코드가 포함된 문자열이 들어있을 수 있으며, th:utext를 사용하여 이 HTML 코드를 안전하게 렌더링할 수 있습니다.

 

th:utext를 사용하면 서버에서 제공된 HTML 코드를 그대로 출력하므로, 이를 악의적으로 활용하는 보안 취약점이 발생할 수 있습니다. 여기에는 다음과 같은 주요 이유가 있습니다.

  • 크로스 사이트 스크립팅 (XSS) 공격: th:utext를 사용하여 사용자 입력을 그대로 출력할 경우, 사용자가 입력한 스크립트 코드가 실행될 수 있습니다. 이로 인해 악의적인 스크립트를 실행하여 개인 정보를 탈취하거나 다른 악의적인 동작을 유도할 수 있습니다.
  • HTML 인젝션: th:utext를 사용하여 HTML을 그대로 출력하면 사용자 입력에 민감한 HTML 태그를 삽입할 수 있습니다. 이렇게 함으로써 웹 페이지의 레이아웃을 망가뜨리거나, 사용자 경험을 개선하는 것 외에도 보안 취약점을 악용할 수 있습니다.
  • 데이터 무결성: th:utext를 사용하면 데이터 무결성을 보장하기 어려울 수 있습니다. 서버에서 제공된 데이터의 일부가 변경되어도 클라이언트 측에서는 이를 감지하지 못하고 출력하게 될 수 있습니다.

보안을 고려하여 th:utext를 사용할 때는 입력 데이터를 신뢰할 수 있는 소스에서 가져오고, 필요한 경우 HTML 이스케이프 함수 등을 사용하여 사용자 입력을 안전하게 처리해야 합니다. Thymeleaf에서는 th:utext를 꼭 필요한 경우에만 사용하고, 그외에는 th:text를 사용하여 텍스트를 출력하는 것이 좋습니다. 또한 입력 데이터를 적절히 검증하고, 서버 측에서 안전한 방법으로 HTML을 생성하는 것이 중요합니다.

 

Spring EL, th:with 

Spring EL :  Spring Framework에서 제공하는 표현 언어로, 서버 측에서 동적 데이터를 템플릿에 삽입하거나 연산을 수행하는 데 사용됩니다. Spring EL은 다음과 같은 기본 구문을 가집니다:

${expression}: EL 표현식은 ${}로 둘러싸여 있습니다. 이를 사용하여 변수, 속성, 메서드 등에 접근할 수 있습니다.

<ul>
    <li th:each="item : ${cart.items}">Product: ${item.name}, Price: ${item.price}</li>
    <li th:each="item : ${cart['items']}">Product: ${item.name}, Price: ${item.price}</li>
    <li th:each="item : ${cart.getItems()}">Product: ${item.name}, Price: ${item.price}</li>
</ul>

 

th:with 속성은 템플릿 내에서 임시 변수를 정의하는 데 사용됩니다. 이를 통해 복잡한 EL 표현식을 단순화하고 가독성을 향상시킬 수 있습니다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>User Profile</title>
</head>
<body>
    <div th:with="fullName=${user.firstName} + ' ' + ${user.lastName}">
        <p th:text="${fullName}"></p>
    </div>
</body>
</html>

위의 예제에서는 th:with를 사용하여 fullName이라는 변수에 user.firstName과 user.lastName의 조합을 할당합니다. 그 후에는 th:text로 fullName 변수를 출력합니다.

 

Thymeleaf Objects 

객체 컨텍스트 (Object Context): Thymeleaf는 웹 애플리케이션의 객체 컨텍스트에 직접 접근할 수 있습니다. 이 객체 컨텍스트에는 주로 컨트롤러에서 모델로 추가한 데이터가 포함됩니다. 

예를 들어, 컨트롤러에서 model.addAttribute("user", user)와 같이 사용자 객체를 모델에 추가하면 Thymeleaf에서 ${user}로 해당 사용자 객체에 접근할 수 있습니다.


요청 속성 (Request Attributes): ${#request}와 같이 사용할 수 있습니다.

응답 속성 (Response Attributes):  ${#response}와 같이 사용할 수 있습니다.

세션 속성 (Session Attributes): ${#session}와 같이 사용할 수 있습니다.

서블릿 컨텍스트 정보에 접근: ${#servletContext} 와 같이 사용할 수 있습니다.
메시지 국제화 (Message Internationalization): ${#messages}와 같이 사용할 수 있습니다.
현재 사용자의 로케일(Language and locality) : ${#locale} 와 같이 사용할 수 있습니다.

 

HTTP 요청의 파라미터는 ${param.parameterName} 형식으로 접근할 수 있습니다. 

스프링 빈의 접근은 ${@BeanName.BeanAttributes} 형식으로 접근할 수 있습니다.

이외의 정보는 아래 URL을 참고 

 

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

 

URL 링크 사용하기 

기본 URL:Thymeleaf에서 기본 URL을 생성하려면 @{} 표현식을 사용합니다. 이것은 컨텍스트 경로를 자동으로 추가합니다.

<a th:href="@{/home}">홈으로 이동</a>

 

위의 예제에서는 "홈으로 이동" 링크를 클릭하면 "/home" URL로 이동합니다.


쿼리 파라미터 적용:쿼리 파라미터를 URL에 추가하려면 ?를 사용하고, 파라미터 이름과 값을 =로 구분한 후 &로 여러 파라미터를 연결합니다. 이 때 th:href 속성을 사용합니다.

<a th:href="@{/search(searchTerm='keyword', page=1)}">검색</a>

 

위의 예제에서는 "검색" 링크를 클릭하면 "/search?searchTerm=keyword&page=1"과 같은 URL로 이동합니다.

경로 변수:경로 변수를 사용하여 URL을 동적으로 생성할 수 있습니다. 경로 변수는 중괄호 {}로 묶어서 표현하며, th:href 속성 내에서 값을 지정할 수 있습니다.

<a th:href="@{/users/{id}(id=123)}">사용자 정보</a>

 

위의 예제에서는 "사용자 정보" 링크를 클릭하면 "/users/123"과 같은 URL로 이동합니다.

경로 변수 + 파라미터:
경로 변수와 파라미터를 조합하여 URL을 생성할 수 있습니다. 경로 변수와 파라미터를 함께 사용할 때도 중괄호 {}와 괄호 ()를 사용하여 지정합니다.

<a th:href="@{/products/{productId}/details(productId=456, view=full)}">제품 상세 정보</a>

 

위의 예제에서는 "제품 상세 정보" 링크를 클릭하면 "/products/456/details?view=full"과 같은 URL로 이동합니다.

 

디폴트 리터럴 이란 ? 

다음과 같이 작은 따옴표를 사용하지 않고 문자열 리터럴을 사용할 수 있습니다:

<p th:text="This is a string literal">Default Text</p>

위의 코드에서 문자열 "This is a string literal"은 작은 따옴표 없이 표현되었습니다. Thymeleaf는 이것을 문자열 리터럴로 인식하고 <p> 태그 내에 그대로 출력합니다.

사용 시 주의점 
작은 따옴표(')를 사용하지 않고 문자열을 표현하는 것은 Thymeleaf의 표준 문법입니다. 그러나 이를 사용할 때 문자열에 특수 문자가 포함된 경우에는 주의해야 합니다. 특수 문자(예: 공백, 특수 기호)가 포함된 문자열은 작은 따옴표(')로 묶어주는 것이 안전합니다.

 

리터럴 대체 문법으로 파이프(|)를 사용하여 문자열을 표현하는 방법은 다음과 같습니다:

<p th:text="|This is a string literal using pipes|">Default Text</p>

위의 코드에서 문자열 "This is a string literal using pipes"는 파이프(|)로 묶여 있으며, 이것은 Thymeleaf에서 문자열 리터럴로 인식됩니다. <p> 태그 내에 그대로 출력됩니다.

이 방법은 작은 따옴표를 사용하지 않고 문자열을 표현할 때 유용하며, 특히 문자열에 작은 따옴표가 포함되어 있는 경우에 유용합니다. 다른 문자열과 구분하기 위해 파이프(|) 안에 특수 문자를 사용할 수도 있습니다.

파이프(|)를 사용한 문자열 리터럴은 변수를 사용하는 것보다 간단하고 가독성이 높을 수 있으며, 특히 단순한 문자열을 출력할 때 유용합니다.

 

반응형

 

연산자

산술 연산자: Thymeleaf는 템플릿에서 산술 연산을 수행할 수 있도록 다양한 연산자를 제공합니다. 이 연산자들은 일반적인 수학 연산과 유사하게 동작합니다.
예를 들어, +는 덧셈, -는 뺄셈, *는 곱셈, /는 나눗셈을 나타냅니다.

<p th:text="${2 + 3}">5</p>

 

비교 연산자: Thymeleaf는 데이터를 비교하기 위한 비교 연산자도 지원합니다. 주로 ==, !=, <, >, <=, >= 등의 연산자를 사용합니다.

<p th:if="${age == 18}">You are 18 years old</p>
<p th:if="${name != 'Alice'}">Hello, not Alice</p>
<p th:if="${price < 100}">Price is less than 100</p>
<p th:if="${age > 21}">You are over 21</p>
<p th:if="${price <= 50}">Price is less than or equal to 50</p>
<p th:if="${age >= 18}">You are an adult</p>

 

조건식 (Conditional Expressions): 조건식은 주어진 조건에 따라 다른 값을 출력하는 데 사용됩니다. Thymeleaf에서는 ? : 연산자를 사용하여 조건식을 표현합니다.

<p th:text="${isMember ? 'Welcome, Member!' : 'Welcome, Guest'}">Welcome</p>

 

엘비스 연산자 (Elvis Operator): Elvis 연산자는 ?:로 표시되며, 변수가 null일 때 대체값을 제공합니다. 이것은 변수가 null일 때 예외를 방지하고 대체값을 출력하는 데 유용합니다.

<p th:text="${username ?: 'Guest'}">Guest</p>

 

No Operation : 값이 없을 경우 무효화 시킬 때 사용됩니다. 이것은 데이터를 출력하거나 조건을 만족하지 않을 때 사용할 수 있습니다.

<p th:text="${value1 ?: _ }">Default Value</p>

 

속성 값 

th:name: th:name 속성은 폼 요소의 name 속성을 설정하는 데 사용됩니다. 이를 통해 폼 데이터가 서버로 전송될 때 해당 이름으로 데이터가 전송됩니다.

<input type="text" th:name="username" />


th:attrappend: th:attrappend 속성은 기존 속성 값에 추가적인 값을 붙이는 데 사용됩니다. 주로 class나 다른 속성에 값을 추가할 때 활용됩니다.

<div class="info" th:attrappend="class='important'">Important Info</div>

 

th:attrprepend: th:attrprepend 속성은 기존 속성 값의 앞에 값을 추가하는 데 사용됩니다. 마찬가지로 class나 다른 속성에 값을 추가합니다.

<div class="info" th:attrprepend="class='important'">Important Info</div>

 

th:classappend: th:classappend 속성은 클래스 속성에 새로운 클래스를 추가하는 데 사용됩니다. 기존 클래스에 새로운 클래스를 추가할 때 유용합니다.

<div class="box" th:classappend="importantClass">Important Box</div>

 

th:checked: th:checked 속성은 라디오 버튼이나 체크 박스의 선택 여부를 동적으로 지정할 때 사용됩니다. 조건에 따라 체크 상태를 변경합니다.

<input type="checkbox" th:checked="${user.subscribed}" />

 

반복 (th : each) 

반복문을 사용하여 컬렉션(리스트, 배열, 맵 등)의 각 요소를 순회하면서 동적으로 템플릿을 생성하고 데이터를 표시하는 데 사용됩니다. 

<tr th:each="fruit, fruitStat : ${users}">
 <td th:text="${fruitStat.count}">username</td>
 <td th:text="${fruit.username}">username</td>
 <td th:text="${fruit.age}">0</td>
 <td>
 index = <span th:text="${fruitStat.index}"></span>
 count = <span th:text="${fruitStat.count}"></span>
 size = <span th:text="${fruitStat.size}"></span>
 even? = <span th:text="${fruitStat.even}"></span>
 odd? = <span th:text="${fruitStat.odd}"></span>
 first? = <span th:text="${fruitStat.first}"></span>
 last? = <span th:text="${fruitStat.last}"></span>
 current = <span th:text="${fruitStat.current}"></span>
 </td>
</tr>

 

th:each 는 Map 도 사용할 수 있는데 이 경우 변수에 담기는 값은 Map.Entry 입니다.


반복 상태 유지

<tr th:each="fruit, userStat : ${users}">

 

반복의 두번째 파라미터를 설정해서 반복의 상태를 확인 할 수 있습니다.
두번째 파라미터는 생략 가능한데, 생략하면 지정한 변수명( fruit ) + Stat 가 됩니다.
여기서는 fruit + Stat = fruitStat 이므로 생략 가능합니다.

 

조건과 주석

th:if: th:if 속성은 지정된 조건이 참인 경우에만 해당 HTML 요소를 생성합니다. 조건이 거짓인 경우 해당 요소가 제거됩니다.

<p th:if="${condition}">이 요소는 조건이 참일 때만 표시됩니다.</p>

 

th:unless: th:unless 속성은 지정된 조건이 거짓인 경우에만 해당 HTML 요소를 생성합니다. 조건이 참인 경우 해당 요소가 제거됩니다. th:if와 반대의 역할을 합니다.

<p th:unless="${condition}">이 요소는 조건이 거짓일 때만 표시됩니다.</p>

 

th:switch, th:case, th:default: th:switch 속성은 다중 조건을 처리하는 데 사용됩니다. th:case 속성은 th:switch와 함께 사용하여 해당 조건이 참일 때만 실행됩니다. th:default는 모든 th:case 조건이 거짓인 경우 실행됩니다.

<div th:switch="${dayOfWeek}">
    <p th:case="'MONDAY'">월요일입니다.</p>
    <p th:case="'TUESDAY'">화요일입니다.</p>
    <p th:case="*">나머지 요일입니다.</p>
</div>

 

HTML 주석: HTML 주석은 <!--로 시작하고 -->로 끝나며, 주석 내용은 <!--와 --> 사이에 위치합니다.
주석 내용은 브라우저에서 렌더링되지 않으며, 오직 소스 코드의 가독성을 높이고 메모를 추가하는 데 사용됩니다.
Thymeleaf에서도 일반적인 HTML 주석을 사용할 수 있습니다.

 

Thymeleaf 파서 주석  : <!--/*로 시작하고 */-->로 끝납니다 , 
Thymeleaf 주석은 브라우저에서는 렌더링되지 않지만, 템플릿을 처리하는 동안 유효한 Thymeleaf 표현식을 포함할 수 있습니다. 이는 주로 조건부 코드를 주석으로 처리하고 나중에 주석을 해제할 때 사용됩니다.

 

Thymeleaf 프로토타입 주석 : <!--/*/ 로 시작하고  /*/--> 로 끝납니다.

HTML 파일을 웹 브라우저에서 그대로 열어보면 HTML 주석이기 때문에 이 부분이 웹 브라우저가
렌더링하지 않는다. 타임리프 렌더링을 거치면 이 부분이 정상 렌더링 된다.

 

th:block

th:block 요소는 HTML 요소를 그룹화하고 렌더링 중에 특정 조건에 따라 그룹 내의 요소를 처리할 수 있는 유용한 태그입니다. 주로 조건부로 HTML 요소를 렌더링하거나 여러 요소를 그룹화할 때 사용됩니다.

th:block 요소에는 다음과 같은 주요 특징이 있습니다:

  • 그룹화: th:block 요소를 사용하여 여러 HTML 요소를 하나로 그룹화할 수 있습니다. 이는 렌더링된 결과에는 영향을 미치지 않고 템플릿의 가독성을 높일 수 있습니다.
  • 조건부 렌더링: th:block 내부의 요소를 조건에 따라 렌더링할 수 있습니다. th:if나 th:unless와 함께 사용하여 요소를 동적으로 제어할 수 있습니다.
  • 반복 요소 그룹화: th:block을 사용하여 th:each와 함께 반복되는 요소들을 그룹화할 수 있습니다. 이는 반복 요소를 렌더링할 때 요소들을 하나의 그룹으로 래핑하는 데 유용합니다.
<th:block th:each="fruit : ${fruits}">
     <div>
     과일 이름 <span th:text="${fruit.name}"></span>
     과일 나이 <span th:text="${fruit.age}"></span>
     </div>
     <div>
     요약 <span th:text="${fruit.name} + ' / ' + ${fruit.age}"></span>
     </div>
</th:block>

 

th:inline

th:inline은 Thymeleaf 템플릿에서 JavaScript, CSS, 또는 자체 정의한 프로세서와 같은 다른 리소스 유형과 템플릿 엔진 간의 혼합 작업을 가능하게 하는 Thymeleaf의 속성입니다.

 

th:inline="javascript": th:inline="javascript"은 JavaScript 코드와 Thymeleaf 표현식을 함께 사용할 수 있도록 허용합니다.
이 모드에서는 JavaScript 코드가 <script> 태그 내부에 있는 것처럼 취급됩니다. 따라서 JavaScript 코드 안에서 ${expression} 형식으로 Thymeleaf 표현식을 사용할 수 있습니다.

<script th:inline="javascript">
    var message = /*[[${message}]]*/ '기본 메시지';
    alert(message);
</script>

 

인라인 사용 후 렌더링 결과를 보면 문자 타입인 경우 " 를 포함해준다. 추가로 자바스크립트에서 문제가 될
수 있는 문자가 포함되어 있으면 이스케이프 처리도 해준다. 

<script th:inline="javascript">
 [# th:each="fruit, stat : ${fruits}"]
 var fruit[[${fruit.count}]] = [[${fruit}]];
 [/]


/!--/* 반환값 */--/>
var fruit1 = {"fruitname":"banana","age":1};
var fruit2 = {"fruitname":"apple","age":2};
var fruit3 = {"fruitname":"melon","age":3};

</script>

 

Template Fragment

 웹 페이지의 일부분을 재사용하기 위해 사용되는 기능입니다. 템플릿 프래그먼트는 특정 영역의 HTML 코드를 별도로 분리하여 템플릿으로 정의하고, 다른 페이지에서 이를 재사용할 수 있게 해줍니다. 

 

템플릿 프래그먼트 정의: 템플릿 프래그먼트는 HTML 파일에서 특정 영역을 정의하고 이름을 붙입니다. 이 영역은 나중에 재사용될 부분입니다.

<!-- 프래그먼트 정의 -->
<div th:fragment="headerFragment">
    <header>
        <!-- 헤더 내용 -->
    </header>
</div>

 

템플릿에서 프래그먼트 사용: 다른 HTML 파일에서 템플릿 프래그먼트를 사용하려면 th:replace나 th:include와 같은 Thymeleaf 속성을 사용하여 프래그먼트를 가져올 위치를 지정합니다.

<!-- 다른 HTML 파일에서 프래그먼트 사용 -->
<div th:replace="fragments/headerFragment :: headerFragment"></div>
<div th:replace="~{fragments/headerFragment :: headerFragment}"></div>
<!-- 파라미터 적용 -->
<div th:replace="~{fragments/headerFragment :: paramFunc ('데이터1', '데이터2')}"></div>

여기서 fragments/headerFragment는 프래그먼트가 정의된 파일의 경로이고, :: headerFragment는 해당 프래그먼트의 이름을 나타냅니다.

프래그먼트 재사용: 프래그먼트를 정의한 후 다른 페이지에서 재사용할 수 있습니다. 이렇게 하면 일관된 디자인을 쉽게 유지하고 공통 요소를 효과적으로 관리할 수 있습니다.

 

Template Layout

템플릿 레이아웃(Template Layout)은 웹 애플리케이션에서 일관된 디자인과 레이아웃을 쉽게 적용할 수 있도록 도와주는 개념입니다. 템플릿 레이아웃을 사용하면 웹 페이지의 공통 부분(헤더, 푸터, 메뉴 등)을 템플릿으로 정의하고, 이러한 템플릿을 각각의 페이지에 쉽게 적용할 수 있습니다.

템플릿 레이아웃을 사용하는 주요 단계는 다음과 같습니다:

템플릿 정의: 웹 애플리케이션에서 사용할 템플릿을 정의합니다. 이 템플릿은 웹 페이지의 구조를 나타내며 공통된 디자인 요소를 포함합니다.

<!-- 템플릿 정의 -->
<!DOCTYPE html>
<html th:replace="~{template/content :: content(~{::title},~{::nav})}"
 xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>웹 애플리케이션 타이틀</title>
</head>
<body>
    <header>
        <!-- 헤더 내용 -->
    </header>
    <nav>
        <!-- 네비게이션 메뉴 -->
    </nav>
    <div>
        <!-- 페이지 내용이 삽입될 자리 -->
    </div>
    <footer>
        <!-- 푸터 내용 -->
    </footer>
</body>
</html>

 

페이지 구성: 각 웹 페이지는 템플릿을 기반으로 구성됩니다. 페이지에서는 th:insert, th:replace, 또는 th:include와 같은 Thymeleaf 속성을 사용하여 템플릿 내부의 특정 영역에 페이지 본문을 삽입합니다.

 

<!DOCTYPE html>
<html th:fragment="content (title, nav)" xmlns:th="http://www.thymeleaf.org">
<head>
 <title th:replace="${title}">레이아웃 타이틀</title>
</head>
<body>
<h1>레이아웃 H1</h1>
<nav th:replace="${nav}">
</nav>
<footer>
 레이아웃 푸터
</footer>
</body>
</html>

 

레이아웃 적용: 각 웹 페이지에서 템플릿을 적용하면, 해당 페이지는 템플릿 내부의 정의된 레이아웃을 따르게 됩니다. 이로써 공통된 디자인 요소와 레이아웃이 쉽게 적용됩니다.

 

반응형

'프레임워크 > Spring' 카테고리의 다른 글

Spring - 메시지 및 국제화 처리  (0) 2023.10.06
Spring MVC - Log 사용하기  (0) 2023.09.28
Spring MVC  (0) 2023.09.28
쓰레드(Thread)  (1) 2023.09.24
서블릿(Servlet)  (0) 2023.09.24
profile

소소한개발팁

@개발자 뱅

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!