자바를 기반으로 하는 템플릿 엔진 중 하나. 템플릿 엔진이란 데이터를 미리 정의된 템플릿에 넣어 HTML을 그리는 소프트 웨어를 가리킨다. 타임리프는 컨트롤러의 로직 수행 결과를 바탕으로 동적 서버 사이드 렌더링(SSR)에 활용된다. 또한 순수 HTML을 유지하며 뷰 템플릿도 사용 가능한 네츄럴 템플릿의 특징을 갖고, 스프링과 유연한 통합을 지원한다.
타임리프는 View단에서 Controller 의 파라미터를 바탕으로 HTML을 그리는 라이브러리이다.
텍스트 변수 출력
<span th:text = "${data}"></span>
타임리프는 주로 HTML 태그 속성에 기능을 정의 하여 사용한다.
텍스트 변수의 출력의 경우 th:text 태그로 출력 가능하다.
뷰가 렌더링 되면 th가 포함된 속성을 인식하여 동적으로 렌더링하게 된다.
이 때 텍스트 변수에 <> 등이 포함되어 있으면 태그가 아닌 문자로 변경시켜주는 HTML 엔티티가 동작한다.
이를 끄고 변수 내 <> 등을 태그로 활용하려면 th:utext 속성을 사용하면 된다.
컨텐츠 내 변수 출력
또한 모든 파라미터 변수는 경우 [[$변수명]]을 통해 컨텐츠 내 출력 가능하다.
<span>[[${data}]]</span>
SpringEL
위와 같이 타임리프는 변수 표현시 ${...} 으로 된 변수 표현식을 사용한다.
이 때 SpringEL은 다양한 표현식으로 변수 접근을 용이하게 해준다.
<span th:text = "${user.name}"> // user 변수의 name 속성에 접근. get함수 자동호출됨.
//user.getUsername() 한 것과 같은 효과.
<span th:text = "${users[0].name}"> // users 리스트 변수의 0번째 객체의 name 속성에 접근
<span th:text = "${userMap['userA'].name}"> //Map에서 userA 찾고 name속성에 접근
기본 객체
${#request}
${#response}
${#session}
같은 기본 객체들 제공.
이때 파라미터는 ${#request.getParameter("paramData") 처럼 불편하게 접근해야 하므로 편의 객체 또한 제공한다.
편의 객체
${param} // request에 바인딩된 파라미터 접근
ex) ${param.paramData} -> paramData 파라미터에 접근
${session} // session에 바인딩된 속성 접근
ex) ${session.sessionData} -> sessionData 속성에 접근
${@} // 스프링 빈 접근
ex) ${@helloBean.hello('Spring!')} -> helloBean 빈 객체에 hello 메서드 호출
유틸리티 객체
${#message} //메시지 처리
${#dates} // 날짜 서식 지원
${#calendars} //Calendar 서식 지원
등 필요에 따라 사용 가능한 여러 유틸리티 객체 제공
타임리프에서 URL 생성시 @{...} 를 사용.
단순 URL
<a th:href="@{/hello}> -> /hello
쿼리 파라미터
<a th:href="@{/hello(param1=${param1}, param2=${param2})}>
-> /hello?param1=data1¶m2=data2
// () 안 부분은 쿼리파라미터가 됨.
경로 변수
<a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}>
-> /hello/data1/data2
// URL 경로상 {} 의 변수가 있다면 () 안은 경로 변수로 처리됨.
경로 변수 + 쿼리 파라미터
@{/hello/{param1}(param1=${param1}, param2=${param2})}
-> /hello/data1?param2=data2
// 경로변수와 쿼리파라미터 동시 사용 가능.
// () 안에서 {} 안 변수와 매핑되는 부분은 경로변수. 나머지는 쿼리파라미터가 됨.
@{...}을 활용하여 동적으로 변하는 URL을 생성할 수 있다.
th: 로 이루어진 속성들은 뷰 렌더링이 아니면 무시된다. - 네츄럴 템플릿의 특징
리터럴은 고정된 변수를 의미한다.
문자 : 'hello' -> 문자의 경우 항상 ''를 포함해야함에 유의
숫자 : 10
불린 : true, false
null : null
<span th:text> = "'hello' + ' world!'">
<span th:text> = "'hello' + ${data}">
<span th:text> = "|hello ${data}|"> // || 활용 리터럴 대체 문법.
th:text 속성 내에서 비교&조건 등의 연산이 가능하다.
//비교
<span th:text="1 gt 10"> -> false
<span th:text="1 != 10"> -> false
//조건
<span th:text="(10 % 2 == 0)? '짝수':'홀수'">
//Elvis 연산자 - 조건문 편의 버전
<span th:text="${data}?: '데이터가 없습니다.'">
//No-opeation - _ 인 경우 th 자체가 없는 것처럼 동작. 네츄럴 템플릿 활용 가능
<span th:text="${data}?: _">데이터가 없습니다.</span>
타임리프는 HTML태그에 th: 속성을 추가하는 방식으로 동작. 기존 HTML에 속성이 존재할 경우 이를 대체하게 됨.
<input type="text" name="A" th:name="B" />
-> 브라우저로 열면 name = A. 뷰 렌더링으로 열면 name = B 가 됨.
타임리프는 기존 HTML 태그 속성에 값을 추가할 수도 있다.
<input type="text", class="text" th:attrappend="class='large'" />
-> class 속성 뒤에 리터럴 large를 추가. textlarge 가 됨.
<input type="text", class="text" th:attrpreappend="class='large'" />
-> class 속성 앞에 리터럴 large를 추가. largetext 가 됨.
타임리프에서 반복은 th:each 속성을 사용한다.
<tr th:each="user, userStat : ${users}">
-> users 리스트 변수를 순회하며 하나씩 user 객체에 담아 태그를 반복 실행함.
리스트 뿐 아니라 배열, Map 등에도 적용할 수 있다.
-> 두번째 파라미터인 userStat은 반복의 상태 확인 객체이며 생략 가능.
태그 내에서 userStat.index, userStat.count, userStat.size 등의 변수를 활용 할 수 있다.
th:if , th:unless 속성으로 사용하며. 뒤의 값이 true 일때만 해당 태그가 반영된다.
<span th:text="'미성년자'" th:if="${user.age lt 20}">
-> user.age 가 20보다 작을때만 '미성년자' 리터럴 문자열 출력
th:switch 와 th:case 를 이용해 스위치 구문도 사용 가능하다.
<td th:switch="${user.age}">
<span th:case="10">10살</span>
<span th:case="20">20살</span>
<span th:case="*">기타</span> -> switch의 디폴트
<!-- -->
HTML 주석은 타임리프가 그대로 남겨둠
<!--/* 내용 */-->
<!--/*-->
내용
<!--*/-->
타임리프 파서 주석은 타임리프가 렌더링시 제거함
<!--/*/
내용
/*/-->
타임리프 프로토타입 주석은 HTML을 그대로 열어보면 주석처리되지만
타임리프 렌더링 시에만 내용이 렌더링됨.
<th:block> 으로 태그를 생성하며 타임리프의 유일한 자체 태그이다.
여러 태그를 묶어서 반복시 사용한다.
<th:block th:each="user : ${users}">
<div>
이름
나이
</div>
<div>
요약
</div>
</th:block>
타임리프는 태그에 속성을 추가하여 사용하는데, 두 개의 div 태그를 한번에 반복처리할 방법이 없기에 이럴 때 블록 태그를 사용한다.
<script th:inline="javascript">
로 사용하며
타임리프에서 자바스크립트를 사용하고. 그 안에서 변수들을 사용할때 여러 편의기능을 제공한다.
자바스크립트 인라인은 세 가지 기능을 한다.
텍스트 렌더링
var username = [[${user.username]]
인라인 전 : username = userA;
인라인 후 : username = "userA";
텍스트 변수를 변수에 대입할시 ""를 자동으로 추가해준다.
JS에서 내추럴 템플릿 적용
var username2 = /[[${user.username}]]/ "test username";
인라인 전 : username2 = /userA/ "test username";
인라인 후 : username2 = "userA"
/* */ 를 활용하여 내추럴 템플릿을 적용하도록 해준다.
객체 JSON 변환
var user = [[${user}]];
인라인 전 : user = BasicController.User(username=userA, age = 10);
인라인 후 : user = {"username":"userA", "age":10);
객체를 JS에서 쓰기 쉽도록 JSON으로 변환해준다.
웹 페이지에 상단, 푸터 등 공통 영역이 존재하고 수정이 필요할 경우 이를 일일이 수정하는 것은 비효율적.
타임리프는 이를 위해 템플릿 조각과 레이아웃 기능을 제공함.
템플릿 생성
<footer th:fragment="copy">
푸터입니다.
</footer>
<footer th:fragment"copyParam (param1, param2)">
파라미터 입니다.
<p th:text="${param1}"></p>
<p th:text="${param2}"></p>
</footer>
템플릿 사용
현 div 태그 안에 위의 copy 조각 삽입
<div th:insert="~{template/fragment/footer :: copy}"</div>
현 div 태그를 위의 copy 조각으로 대체
<div th:replace="~{template/fragment/footer :: copy}"</div>
copy 조각으로 대체. 단순 표현식
<div th:replace="template/fragment/footer :: copy"</div>
copyParam을 메서드처럼 사용. 데이터1, 데이터2를 넘겨주며 호출.
<div th:repalce="~{template/fragment/footer ::
copyParam ('데이터1', '데이터2')}"</div>
범용 레이아웃을 만들어놓고, 조각을 대입하여 사용
범용 레이아웃
<html th:fragment="layout (title, content)">
확장 Main
<html th:replace="~{template/layoutExtend/layoutFile
:: layout(~{::title}, ~{::section})};
확장 Main은 범용 레이아웃에게 자신의 title 태그와 section 태그 값들을 넘겨준다.
범용 레이아웃은 이를 title과 content 삼아 자신을 렌더링 한다.
확장 Main은 replace를 통해 자신을 2번 결과로 대체한다.
-> 즉 확장 Main은 넘겨주는 파라미터에 따라 변경된 레이아웃을 자신으로 하게됨.
본 글은 김영한님의 "스프링 MVC 2편 - 백엔드 웹 개발 활용 기술" 강의내용 및 이해한 내용을 정리한 것입니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard