thymeleaf 문법 정리

mark1106·2023년 12월 1일
0

spring

목록 보기
1/5
post-thumbnail

thymeleaf 특징

  • 서버 사이드 HTML 렌더링
    - 백엔드 서버에서 HTML을 동적으로 렌더링해준다.

  • 네츄럴 템플릿
    - 타임리프로 작성된 파일된 파일을 웹 브라우저에서 열면 HTML 결과 확인 가능하다(순수 HTML을 유지하며 뷰 템플릿을 사용할 수 있는 것을 네츄럴 템플릿이라고 한다.)

  • 스프링과 자연스럽게 통합되어 편리하게 사용 가능

thymeleaf 기본 표현식

◦ 변수 표현식: ${...}
◦ 선택 변수 표현식: *{...}
◦ 메시지 표현식: #{...}
◦ 링크 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: _


thymeleaf 사용법

<html xmlns:th="[http://www.thymeleaf.org](http://www.thymeleaf.org/)">
-> 타임리프 사용 시 항상 적어줘야 함.

텍스트

text
기본 텍스트 출력

  • <span th: text=&{data}">

  • [[${data}]]

utext

  • th:text -> th:utext
  • [[...]] -> [(...)]

text 내용을 작성할 때 <b>와 같은 태그들을 넣어 text를 진하게 하려고 한다.

하지만 출력을 보면 강조되지 않고 <b>태그가 그대로 출력되는 것을 볼 수 있다.

웹 브라우저에서 < 는 태그의 시작이므로 문자로 인식하지 않기 때문에 방법이 필요.(< → &lt, > → &gt)

기본적으로 타임리프는 escape(특수 문자를 HTML 엔티티로 변경하는 것)를 제공하므로 그대로 사용하기 위해 utext를 사용해줘야 한다.

변수

@Data
class User{
	private String username;
    private int age;
}

타임리프에서 User 객체의 필드를 접근할 때 세 가지 방법으로 접근할 수 있다.

  • ${user.username}
  • ${user['username']}
  • ${user.getUsername()}

기본 객체들

타임리프가 제공하는 기본 객체들을 사용할 수 있다.

  • ${param.paramData} : session과 model에 담아준 정보들을 다음과 같이 출력할 수 있다. 또한 @RequestParameter와 같이 많이 쓰이는 것들은 param.(이름) 으로 바로 접근 가능하다.
  • ${session.sessionData} : session에 넣어준 sessionData인 Hello Session이 출력되는 것을 볼 수 있다.
  • ${@helloBean.hello('Spring!')} : 우리가 스프링 빈으로 등록한 helloBean을 바로 접근할 수 있다.

날짜 객체


다음과 같이 LocalDateTime.now()를 활용하여 현재 시간에 대한 정보를 얻을 수 있다.

<span th:text="${#temporals.day(localDateTime)}"></span></li>
<span th:text="${#temporals.month(localDateTime)}"></span>

URL 링크

타임리프에서 URL을 생성할 때는 @{...} 사용

  • 단순한 URL : <a th:href="@{/hello}">
    업로드중..
  • 쿼리 파라미터 : <a th:href="@{/hello(param1=${param1}, param2=${param2})}">

업로드중..

  • 경로 변수 : <a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}">
    업로드중..
  • 경로 변수 + 파라미터 : <a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}">
    업로드중..

리터럴(Literals)

리터럴 : 소스 코드상 고정된 값
ex)
String a = “Hello
int a = 10 * 20

타임리프에서 문자 리터럴은 항상 ‘(작은 따옴표)'로 감싸야 한다.

<span th:text=”’hello’”>
문자를 항상 ‘로 감싸는 것은 귀찮으니 공백없이 쭉 이어지면 하나의 토큰으로 인식해 따옴표를 생략 가능하다.
ex) A-Z , a-z , 0-9 , [] , . , - , _

리터럴 표현하는 4가지 방식

  • “’hello’ + ‘ world!”
  • “’hello world!’”
  • “’hello ‘ + ${data}”
  • “|hello ${data}|”

→ 마지막 문법처럼 || 안에 내용을 작성하면 문자 그대로 출력 가능하다.

연산

<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>

업로드중..

  • 비교연산 : HTML 엔티티 사용하는 부분 주의 → > (gt), < (lt), >= (ge), <= (le), ! (not), == (eq), != (neq, ne)
  • 조건식 : 자바의 조건식과 유사
  • Elvis 연산자 : 조건식의 편의 버전
  • No-Operation : _ (조건에 만족하지 않을 때)인경우 타임리프가 실행되지 않는 것 처럼 동작 → th:text="${nullData}?: _” 이 부분이 없는 것과 같다

속성 값 설정

타임리프 태그 속성(Attribute)

타임리프는 HTML 태그에 th:* 속성을 지정하는 방식으로 동작한다.

th:* 속성을 적용하면 기존 속성을 대체하고 없으면 새로 만든다.

<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/>

업로드중..

  • th:attrapend, th:attrprepend, th:classappend 모두 기존 class에 추가하여 새로운 class를 만든다
  • check 상자에서 check 표시를 하려면 check=”checked” 를 해야하는데 boolean 값으로 쉽게 만들어주기 위해 true -> checked , false → 속성 값 삭제 해준다.

반복

th:each 를 활용하여 코드 반복을 할 수 있다.

<tr th:each="user : ${users}">
    <td th:text="${user.username}">username</td>
    <td th:text="${user.age}">0</td>
  </tr>

조건

if : 만족하면
unless : 만족하지 않으면

<td>
 <span th:text="${user.age}">0</span>
 <span th:text="'미성년자'" th:if="${user.age lt 20}"></span>
 <span th:text="'미성년자'" th:unless="${user.age ge 20}"></span>
</td>

th:if=”${user.age lt 20}” : 나이가 20 미만이면 출력

th:unless=”${user.age ge 20}” : 나이가 20 이상이 아니면 출력

주석

  1. 표준 HTML 주석

자바스크립트 표준 HTML 주석은 타임리프가 렌더링하지 않고 그대로 남겨둔다.

<!--
<span th:text="${data}">html data</span>
-->
  1. 타임리프 파서 주석

타임리프의 진짜 주석으로 렌더링에서 주석 부분 제거

<!--/* [[${data}]] */-->
or
<!--/*-->
<span th:text="${data}">html data</span>
<!--*/-->
  1. 타임리프 프로토타입 주석

HTML파일을 그대로 열면 주석처리가 되고, 타임리프 렌더링 한 경우에만 보인다.

<!--/*/
<span th:text="${data}">html data</span>
/*/-->

블록

<th:block> : HTML 태그가 아닌 타임리프의 유일한 자체 태그

<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>
</th:block>

반복문을 이용하여 <div> 를 각각 출력하는 것과 같이 애매한 상황에서 사용

자바스크립트 인라인

자바스크립트를 사용할 때는 th:inline

속성을 넣어줘야 한다.

<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";*

(인라인 사용 후 결과를 보면 주석 부분이 제거되고 기대한 “userA”가 정확하게 적용)

  • 객체

var user = [[${user}]];

인라인 사용 전 → var user = BasicController.User(username=userA, age=10);

인라인 사용 후 → var user = {"username":"userA","age":10};

(인라인 사용 후 객체를 JSON으로 변환)

템플릿 조각

웹 페이지의 공통 영역들을 중복해서 사용하는 것은 비효율적이다.

따라서 템플릿을 사용하면 공통 영역들을 한번에 관리할 수 있다.

<footer th:fragment="copy">
 푸터 자리 입니다.
</footer>

template/fragment/footer :: copy : template/fragment/footer.html 템플릿에 있는
th:fragment="copy" 라는 부분을 템플릿 조각으로 가져와서 사용한다는 의미이다

부분 포함 insert : th:insert 는 현재 태그 내부에 추가

<div th:insert="~{template/fragment/footer :: copy}"></div>

부분 포함 replace : th:replace 는 현재 태그( div )를 대체한다.

<div th:replace="~{template/fragment/footer :: copy}"></div>

파라미터 사용 : 파라미터를 넘겨 동적으로 조각을 렌더링할 수 있다.

<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>

템플릿 레이아웃

템플릿 조각은 일부 코드 조각을 가져와 사용했다면 템플릿 레이아웃은 코드 조각을 레이아웃에 넘겨서 사용하는 방법이다.

메인 레이아웃이 있고 거기에 필요한 코드 조각을 전달해 View를 완성한다.

head

<head th:replace="template/layout/base :: common_header(~{::title},~{::link})">
 <title>메인 타이틀</title>
 <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
 <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>

common_header(~{::title},~{::link}) 이 부분에 각각 title과 link가 전달된다.

그리고 메인 레이아웃인 template/layout/base 에 전달되어 titlelink가 렌더링된 head로 교체된다.

html

<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title}, ~{::section})}" xmlns:th="http://www.thymeleaf.org">
<head>
  <title>메인 페이지 타이틀</title>
</head>
<body>
<section>
  <p>메인 페이지 컨텐츠</p>
  <div>메인 페이지 포함 내용</div>
</section>
</body>
</html>

head와 달리 html 전체 페이지를 교체하는 방법이다.

template/layoutExtend/layoutFile

<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">

titlesection에 내용을 template/layoutExtend/layoutFile 에 전달하여 렌더링된 html로 교체된다.

이 때 템플릿 레이아웃은 th:fragment 로 표현한다.


📚 참고 - 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 by 김영한
profile
뒤돌아보면 남는 것은 사진, 그리고 기록 뿐

0개의 댓글