타임리프
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>
[참고] 인프런 김영한님 강의를 공부한 내용입니다.
'Spring' 카테고리의 다른 글
[스프링 MVC2] 애노테이션 검증 (Bean Validation) (0) | 2022.06.15 |
---|---|
[스프링 MVC2] 메시지, 국제화 (0) | 2022.06.15 |
[스프링 MVC1] 서블릿, MVC 패턴 (2/2) (0) | 2022.06.13 |
[스프링 MVC1] 서블릿(Servlet), MVC 패턴 (1/2) (0) | 2022.06.13 |
[Spring] 스프링 핵심 개념 (2/2) (0) | 2022.06.13 |