타임리프

 

Thymeleaf is a modern server-side Java template engine.
The main goal of Thymeleaf is to provide highly-maintainable way of creating templates.
it builds on the concept of Natural Templates.

 

타임리프는 순수 HTML로 사용할 수 있으면서 서버 사이드 렌더링(SSR)으로서 뷰 템플릿의 역할도 하는 네츄럴 템플릿이다.

스프링과 자연스럽게 통합되어 스프링의 다양한 기능을 편리하게 사용할 수 있는 장점이 있다.

 

 

 

기본 표현식

  • 타임리프는 기본적으로 HTML 태그의 속성에 기능을 정의해서 동작한다.
  • 뷰 템플릿으로 실행하지 않을 때는 기본 HTML 태그로 동작하기 때문에 네츄럴 템플릿이라고 한다.

 

 

텍스트

<li>th:text 사용 <span th:text="${data}"></span></li>
<li>컨텐츠 안에서 직접 출력 = [[${data}]]</li>

 

HTML 엔티티

  • HTML 태그를 순수 문자 용도로 사용하도록 변경(이스케이프)하는 방법
  • th:text, [[...]] 의 경우 기본적으로 이스케이프를 적용
  • 이스케이프를 적용하지 않으려면 th:utext, [(...)] 로 사용 (HTML 태그로 동작함)
  • 이스케이프를 적용하지 않을 경우 HTML 렌더링 오류 위험

 

 

변수 표현

  • 스프링이 제공하는 변수 표현식 SpringEL
<li> user 객체 프로퍼티 접근 <span th:text="${user.username}"></span></li>
<li> List 접근 <span th:text="${users[0].username}"></span></li>
<li> Map 접근 <span th:text="${userMap['userA'].username}"></span></li>
  • 지역 변수 선언
<!-- 변수(user)는 선언한 태그 내에서만 사용 가능 -->
<div th:with="user=${users[0]}">
	<p><span th:text="${user.username}"></span></p>
</div>

 

유틸리티 객체

  • 문자, 숫자, 날짜, URI, 객체, 배열등을 편리하게 다루는 다양한 유틸리티 객체들 (thymeleaf.org 참고)
<!-- LocalDateTime Format Example -->
<span th:text="${#temporals.format(localDateTime, 'yyyy-MM-dd HH:mm:ss')}"></span>

 

URL 링크

<!-- path variable + query parameter -->
<li><a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}"></a></li>

 

리터럴

  • 문자 리터럴은 작은 따옴표(' ')로 감싸거나 리터럴 대체 문법으로 처리를 해야 된다.
<li>따옴표 사용<span th:text="'hello ' + ${data}"></span></li>
<li>리터럴 대체<span th:text="|hello ${data}|"></span></li>

 

Checked

<!-- HTML에서는 checked 속성이 false여도 체크가 되는데 타임리프는 false일 경우 checked 옵션이 사라짐 -->
<input type="checkbox" name="active" th:checked="false" />

 

반복문

  • th:each 는 List 뿐만 아니라 배열, Map, java.util.Iterable java.util.Enumeration 을 구현한 모든 객체를 반복에 사용 가능
  • 두번째 파라미터를 설정해서 상태 확인 가능 (생략 시 변수명 + 'Stat', 예제에서는 userStat)
  • index, count(1부터 시작 index), size, current (현재 객체) 등 다양한 반복 상태 나타내는 기능
<!-- userStat 생략 가능 -->
<tr th:each="user, userStat : ${users}">
	<td th:text="${user.username}">username</td>
    <td th:text="${user.age}">age</td>
</tr>

 

조건문

  • th:if, th:unless
  • 조건 충족하지 않을 경우 해당 태그 자체가 사라짐
  • 스위치문 th:switch, th:case, th:*(default)

 

블록

  • HTML이 아닌 유일한 타임리프 자체 태그
  • HTML 태그 사용하기 애매한 경우에 사용, th:block은 렌더링시 제거
<th:block th:each="user : ${users}"></th:block>

 

자바스크립트 인라인

  • 자바스크립트에서 타임리프를 편리하게 사용할 수 있게 지원해주는 자바스크립트 인라인 기능
  • 객체를 JSON으로 자동 변환
<script th:inline="javascript">

	<!-- 렌더링시 주석이 제거되면서 [[${user.username}]] 출력 -->
    var username2 = /*[[${user.username}]]*/ "test username";
    
    
    <!-- 자바스크립트 인라인 each문 -->
    [# th:each="user, stat : ${users}"]
    	var user[[${stat.count}]] = [[${user}]];
    [/]
      
</script>

 

 

템플릿 조각

 <footer th:fragment="copy">
 	footer content
 </footer>

<footer th:fragment="copyParam (param1, param2)">
	<p th:text="${param1}"></p>
    <p th:text="${param2}"></p>
</footer>
<!-- ~{template/fragment/footer :: copy} = ~{'파일경로' :: 'fragment name'} -->
<!-- insert 사용 시 현재 태그 내부에 생성 -->
<div th:insert="~{template/fragment/footer :: copy}"></div>

<!-- replace 사용 시 현재 태그를 대체 -->
<div th:replace="~{template/fragment/footer :: copy}"></div>

<!-- 파라미터 넘기기 -->
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터 2')}"></div>

 

템플릿 레이아웃

  • 공통으로 사용하는 css javascript 같은 정보들이 있는데이러한 공통 정보들을 한 곳에 모아두고공통으로 사용하지만각 페이지마다 필요한 정보를 더 추가해서 사용하고 싶은 경우 템플릿 레이아웃 적용
  • html 자체를 레이아웃 하는 것도 가능
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="common_header(title,links)">
	<title th:replace="${title}">레이아웃 타이틀</title>
	
    <!-- 공통 -->
    <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}">
  	<link rel="shortcut icon" th:href="@{/images/favicon.ico}">
  	<script type="text/javascript" th:src="@{/sh/scripts/codebase.js}"></script>

	<!-- 추가 -->
	<th:block th:replace="${links}" />
</head>
<!-- ::title 은 현재 페이지의 title 태그들을 전달한다.-->
<!-- ::link 는 현재 페이지의 link 태그들을 전달한다.-->
<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>

 

폼 기능

  • th:object 커맨드 객체를 지정
  • *{...} 선택 변수 식, th:object 에서 선택한 객체에 접근한다.
  • th:field : HTML 태그의 id name value 속성을 자동으로 처리
  • th:field는 정상 상황에는 모델 객체의 값을 사용하지만, 오류가 발생하면 FieldError 에서 보관한 값을 사용해서 값을 출력

 

체크 박스

  • HTML 체크 박스는 체크가 안되면 서버로 값 자체를 보내지 않기 때문에 경우에 따라 사용자가 체크되어 있던 값을 해제한 건지 판단하기가 어려움
  • 스프링 MVC는 이를 위해 _open 이라는 히든 필드를 추가로 하나 만들어서 체크 해제를 인식할 수 있다. (히든 필드는 항상 전송)
  • 따라서 체크를 해제하면  open 은 전송되지 않고 _open 이 전송되는데이 경우 체크를 해제했다고 판단할 수 있다.
  • 타임리프를 사용하면 히든 필드(_open)를 자동으로 생성
<input type="checkbox" id="open" name="open" class="form-check-input">
<!-- 히든 필드 추가 -->
<input type="hidden" name="_open" value="on"/>
<!-- 타임리프는 체크박스의 히든 필드도 자동으로 해결 -->
<input type="checkbox" id="open" th:field="${item.open}" class="form-check-input">

 

멀티 박스

  • @ModelAttribute를 컨트롤러에 있는 별도의 메서드에 적용하면 해당 컨트롤러를 요청할 때 메서드에서 반환한 값이 자동으로 model에 담기게 된다.
  • 멀티 체크박스를 th:each로 생성 시 id를 임의로 item1, item2, item3 .. 이런식으로 생성
<!-- multi checkbox -->
<div>
	<div th:each="item : ${items}" class="form-check form-check-inline">
		<input type="checkbox" th:field="*{items}" th:value="${item.key}" class="form-check-input">
		<label th:for="${#ids.prev('items')}" th:text="${item.value}" class="form-check-label">서울</label>

 

 

 

 

 

[참고] 인프런 김영한님 강의를 공부한 내용입니다.

+ Recent posts