Front-End/thymeleaf

Thymeleaf 공부하기 (1) : 텍스트, 변수, 기본 객체, 유틸리티 객체와 날짜, url 링크, 리터럴, 연산

TerianP 2022. 10. 11.
728x90

본 Thymeleaf 공부하기 시리즈는 김영한 님의  스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 강의를 듣고 작성한 내용입니다.

 

들어가면서

몇몇 포스팅에서 계속 이야기해왔지만 나는 정말정말 HTML 에 서툴다. CSS 는 말 할 것도 없고.

다만 어쨌든 내가 만든 프로젝트의 결과물들을 단순한 자바 코드로 보여 줄 수는 없었기에 HTML 을 공부...가 아니라 검색해서 사용해왔다.

다행히도 JSP 와 JSTL 을 배운 경험이 있어서 JSP 로 프론트 페이지를 겨우 구현할 수는 있었다.

사실 jsp 를 쓰면서 굉장히 불편했던 점이 많았다. JSP의 특성상 HTML 파일에 JAVA 코드가 들어갈 때가 많았고, JAVA 코드가 아닌 JSTL 을 사용해서 구현한다고 하더라도 JSTL 과 HTML, CSS 까지 모두 사용할때면 정말정말 머리아플때가 많았다 ㅠ.ㅠ

그래서 이번 기회에 spring 과 연동이 정말 잘되는? Thymeleaf 를 공부하고 정리해보려 한다. 아무리 백엔드 개발자라고 하더라도 결국 프론트를 아무것도 모를 수 없기에 그리고 무엇보다, jsp 과 jstl 을 벗어나고 싶다!!

 

1. 타임리프의 특징

- 서버 사이드 HTML 랜더링(SSR)
   => SSR 이란 서버 사이드 HTML 랜더링을 의미한다. 타임리프는 백엔드 서버에서 HTML 을 동적으로 랜더링 하는 용도로 사용한다

- 네츄럴 템플릿
   => 타임리프는 순서 HTML 을 유지하는 특징이 있다.
   => 타임리프로 작성한 파일은 HTML 을 유지하기 때문에 웹 브라우저에서 파일을 직접 열어도 내용을 확인 할 수 있고, 서버를 통해 뷰 템플릿을 거치면 동적으로 변경된 결과를 확인 할 수 있다.
   => HTML 이 뒤죽박죽 섞여서 브라우저에서 정상적인 HTML 결과를 확인 할 수 없다 : 대표적으로 JSP
   => 타임 리프는 해당 파일 그대로 웹 브라우저에서 열어도 정상적인 HTML 결과를 확인 할 수 있다. 물론 이 경우 동적인 결과가 랜더링 되서 보여지지는 않는다. 
  => 이렇게 순수 HTML 그대로 유지하면서 뷰 템플릿도 사용할 수 있는 타임리프의 특징을 내츄럴 템플릿 이라고 한다

- 스프링 통합 지원
  => 타임리프는 스프링과 자연스럽게 통합되고, 스프링의 다양한 기능을 편리하게 사용할 수 있게 제공한다

 

2. HTML 엔티티

웹 브라우저는 < 를 HTML 테그의 시작으로 인식한다. 따라서 < 를 테그의 시작이 아니라 문자로 표현할 수 있는 방법이 필요한데, 이것을 HTML 엔티티라 한다. 그리고 이렇게 HTML에서 사용하는 특수 문자를 HTML 엔티티로 변경하는 것을 이스케이프(escape)라 한다. 그리고 타임리프가 제공하는 th:text , [[...]] 는 기본적으로 이스케이스(escape)를 제공한다

 

1) Unescape

타임리프는 다음 두 기능을 제공한다.

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

 

 

3. 텍스트 출력하기 

텍스트를 출력하는 방법은 크게 2가지가 있다.
태그를 사용하는 th:text="${model attribute name}" 와
태그 없이 사용하는 [[${model attribute name}]]
<body>
    <h1>컨텐츠에 데이터 출력하기</h1>
    <ul>
        <li>th:text 사용
            <span th:text="${data}"></span>
            <li>컨텐츠안에 직접 출력하기 = [[${data2}]]</li>
            <li>태그 기능 유지 = <span th:text="${esc}"></span></li>
            <li>unescaped 태그까지 포함해서 그대로 출력 <span th:utext="${un}"></span></li>
        </li>
    </ul>

<h1><span th:inline="none">[[..]] vs [(..)]</span></h1>
<ul>
    <li><span th:inline="none">[[...]] = </span>[[${em}]]</li>
    <li><span th:inline="none">[(...)] = </span>[(${em})]</li>
</ul>
</body>

 

4. 변수 - SpringEL

1) 변수 출력

타임리프에서 변수를 사용할 때는 변수 표현식을 사용한다.
변수 표현식 : ${...}
이 변수 표현식에는 스프링 EL 이라는 스프링이 제공하는 표현식으로도 사용 가능
<h1>SpringEL 표현식</h1>
<ul>Object : attributeName.변수명, ['변수명'], .getter메서드
    <li>${user.username} = <span th:text="${user.username}"></span></li>
    <li>${user['username']} = <span th:text="${user['username']}"></span></li>
    <li>${user.getUsername()} = <span th:text="${user.getUsername()}"></span></li>
</ul>
<ul>List : list[인덱스].변수명, ['변수명'], .getter메서드
    <li>${users[0].username} = <span th:text="${list[0].username}"></span>
    </li>
    <li>${users[0]['username']} = <span th:text="${list[0]['username']}"></span>
    </li>
    <li>${users[0].getUsername()} = <span th:text="${list[0].getUsername()}"></span></li>
</ul>
<ul>Map : map['key'].변수명, ['변수명'], .getter메서드
    <li>${userMap['레이너'].username} = <span th:text="${map['레이너'].username}"></span></li>
    <li>${userMap['레이너']['username']} = <span th:text="${map['레이너']['username']}"></span></li>
    <li>${userMap['레이너'].getUsername()} = <span th:text="${map['레이너'].getUsername()}"></span></li>
</ul>
</body>

 

2) 지역 변수 생성

지역 변수 생성은 th:with="변수명=${변수에 담을 값}"
이때 생성된 지역 변수는 해당 태그 내에서만 사용 가능하다
아래 코드의 경우 div 내에서만 사용 가능!!
<h1>지역 변수 - (th:with)</h1>
<div th:with="var=${list[1]}">
    <p>두번째 사람의 이름은 <span th:text="${list[1].username}"></span></p>
</div>

 

5. 기본 객체

타임리프는 웹에서 사용하는 기본 객체들을 사용 할 수 있도록 제공한다
request, response, session, servletContext, locale, HTTP 요청 파라미터, 스프링 빈
<h1>식 기본 객체 (Expression Basic Objects)</h1>
<ul>
    <li>각 객체.get('name') 해서 request에 담긴 값들을 꺼내올 수 있다</li>
    <li>request = <span th:text="${#request}"></span></li>
    <li>#request. = <span th:text="${#request.getAttribute('obj')}"></span></li>
    <li>response = <span th:text="${#response}"></span></li>
    <li>session = <span th:text="${#session}"></span></li>
    <li>servletContext = <span th:text="${#servletContext}"></span></li>
    <li>locale = <span th:text="${#locale}"></span></li>
</ul>

<h1>편의 객체</h1>
<ul>
    <li>Request : param.파라미터명 = <span th:text="${param.paramData}"></span></li>
    <li>session = session.세션명 <span th:text="${session.sessionData}"></span></li>
    <li>spring bean = @Bean이름.Bean <span th:text="${@springBean.Bean('Spring!')}"></span></li>
</ul>

 

6. 유틸리티 객체와 날짜

타임리프는 문자, 숫자, 날짜, URI 등을 편리하게 다루는 다양한 유틸리티 객체들을 제공한다
대표적으로 #message, #uris, #dates, #calendars, #temporals, #numbers, #strings, #objects, #bools, #arrays, #lists, #sets, #maps, #ids
이중 메시지와 관련한 #message, 아이디와 관련한 #ids 정도는 기억하자. 나머지는 그냥 있구나 정도만 알고있고, 쓸때 검색하자
<body>
<h1>LocalDateTime</h1>
<ul>
    <h2>날짜 유틸리티</h2>
    <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>
</body>

 

7. url 링크

 

<h1>URL 링크</h1>
<ul>
  <li>url : <a th:href="@{https:/terianp.tistory.com/}">기0본 url</a></li>
  <li>url?param1="data1"&param2="data2" : <a th:href="@{https:/terianp.tistory.com/(param1=${param1}, param2=${param2})}">파라미터 추가</a></li>
  <li>url/data1/data2 : <a th:href="@{https:/terianp.tistory.com/{param1}/{param2}(param1=${param1}, param2=${param2})}">path variable</a></li>
  <li>url/data1?param2="data2" : <a th:href="@{https:/terianp.tistory.com/{param1}(param1=${param1}, param2=${param2})}">path variable + query parameter</a></li>
</ul>

 

 

8. 리터럴

리터럴은 소스 코드상에 고정된 값을 말하는 용어
타임리프에서 문자 리터럴은 항상 원칙적으로 ' (작은 따옴표)로 감싸야 한다. 특히 중간에 공백이 있으면 하나의 의미있는 토큰으로 인식되지 않는다.
따라서 "hello world" 가 아닌 " '(작은 따옴표)hello world' " 로 만들어야 한다
혹은 작은 따옴표를 대체하기 위해 "|문자 ${..}|" 를 사용할 수도 있다
<h1>리터럴</h1>
<ul>
    <!--주의! 다음 주석을 풀면 예외가 발생함-->
    <!-- <li>"hello world!" = <span th:text="hello world!"></span></li>-->
    <li>'hello' + ' world!' = <span th:text="'hello' + ' world!'"></span></li>
    <li>'hello world!' = <span th:text="'hello world!'"></span></li>
    <li>'hello ' + ${data} = <span th:text="'hello ' + ${data}"></span></li>
    <li>리터럴 대체 |hello ${data}| = <span th:text="|hello ${data}|"></span></li>
</ul>

 

9. 연산

비교연산: HTML 엔티티를 사용해야 하는 부분에 주의할 것
조건식: 자바의 조건식과 유사하다. 
Elvis 연산자: 조건식의 편의 버전, thymeleaf 버전!
No-Operation: _ 인 경우 마치 타임리프가 실행되지 않는 것 처럼 동작한다.
즉 ${...} 의 내용이 없을 때 출력되는 내용을 태그 안에 작성해두고 사용하면 ${...} 의 내용이 null 일 때와 아닐 때는 구분하여 편리하게 사용 가능
<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 연산자 : 조건식의 축약 버전 => ${data}:? 했을 때 값이 있으면 ${data} 출력, 없으면 데이터가 없습니다 출력
        <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 태그 안 내용 출력</span></li>
        </ul>
    </li>
</ul>


Thymeleaf 표현법 정리 : 아주 중요

표현법 설명
 <span th:text="${model attribute name}"></span>
태그 사용하여 Attribute 내용 출력
<span>[[${model attribute name}]]</span> 태그 없이 Attribute 내용 출력
${attributeName.변수명} 
${attributeName.['변수명']}
${attributeName.getter메서드}
Attribute 내용 출력 - 단순 Object
${list[인덱스].변수명} 
${list[인덱스].['변수명']}
${list[인덱스].getter메서드}
Attribute 내용 출력 - List
${map['key'].변수명} 
${map['key'].['변수명']}
${map['key'].getter메서드}
Attribute 내용 출력 - Map
th:with="변수명=${변수에 담을 값}" 태그 내에서 사용가능한 지역 변수 생성
${#request}
${#response}
${#session}
${#servletContext}
${#locale}
Thymeleaf 에서 제공하는 기본 객체
객체.get('name') 을 사용해서 값들을 꺼내올 수 있다
파라미터 : ${param}
session : ${session}
Thymeleaf 에서 제공하는 편의 객체
마찬가지로 객체.get('name') 해서 값들을 꺼내 올 수 있다
springBean : ${@Bean이름.메서드명('매개변수')} Thymeleaf 에서 제공하는 편의 객체
SpringBean 에 접근 가능하도록 하며 Bean 의 메서드를 실행할 수 있다
${#temporals.format(localDateTime, 'yyyy-MM-dd HH:mm:ss')} 자바 객체인 localDateTime 을 temporals 를 이용해서 날짜를 특정한 포멧으로 출력 가능
@{url} 단순 url
@{url(param1=${param1}, param2=${param2})} 쿼리 파라미터
@{url/param1/{param2}(param1=${param1}, param2=${param2})} 경로 변수
@{url/{param1}(param1=${param1}, param2=${param2})}  쿼리파라미터 + 경로 변수
| 문자 ${...} | 리터럴 대체 문법
gt, >=, == , != gt : 크다
>= : 크거나 같다
== : 같다
!= : 다르다
<span th:text="${data}?: '데이터가 없습니다.'"></span> Elvis 연산자 : ${data}?: => 3항연산의 thymeleaf 형
데이터가 있는 경우 ${...} 안에 있는 내용이 출력되고, 데이터가 없는 경우 : 뒤에 있는 내용이 출력된다
<span th:text="${data}?:_">span 태그 안 내용 출력</span> No-Operation : ${data}?:_(언더바)
${...} 의 내용이 없을 시 - null 일 때 태그 안에있는 내용이 출력된다

 


Reference

공식 사이트

 

Thymeleaf

Integrations galore Eclipse, IntelliJ IDEA, Spring, Play, even the up-and-coming Model-View-Controller API for Java EE 8. Write Thymeleaf in your favourite tools, using your favourite web-development framework. Check out our Ecosystem to see more integrati

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

 

 

공식 메뉴얼 - 스프링 통합

 

Tutorial: Thymeleaf + Spring

Preface This tutorial explains how Thymeleaf can be integrated with the Spring Framework, especially (but not only) Spring MVC. Note that Thymeleaf has integrations for both versions 3.x and 4.x of the Spring Framework, provided by two separate libraries c

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

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

 

댓글