네츄럴 템플릿
타임리프는 순수 html 을 유지하는 특징이 있다.
타임리프로 작성한 파일은 HTML을 유지하기 떄문에 웹 브라우저에서 파일을 직접 열어도 확인 할 수 있고 , 서버를 통해 뷰 템플릿을 거치면 동적으로 변경된 결과를 확인 할 수 있다.
이스케이프
<b> </b> 이런 tag들을 그대로 내보내지 않는다. 타임리프는 기본으로 이스케이프 처리를 해준다.
각각 아래의 라인이 unescape 하는 방법이다.
<li>th:text 사용 <span th:text="${data}"></span></li>
<li>th:text 사용 <span th:utext="${data}"></span></li>
<li> 컨텐츠 안에서 직접 출력하기 = [(${data})]</li>
<li>컨텐츠 안에서 직접 출력하기 = [[${data}]]</li>
Object , List ,Map 꺼내는 방법
<h1>SpringEL 표현식</h1>
<ul>Object
<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
<li>${users[0].username} = <span th:text="${users[0].username}"></span></li>
<li>${users[0]['username']} = <span th:text="${users[0]['username']}"></span></li>
<li>${users[0].getUsername()} = <span th:text="${users[0].getUsername()}"></span></li>
</ul>
<ul>Map
<li>${users['userA'].username} = <span th:text="${userMap['userA'].username}"></span></li>
<li>${users['userA']['username']} = <span th:text="${userMap['userA']['username']}"></span></li>
<li>${users['userA'].getUsername()} = <span th:text="${userMap['userA'].getUsername()}"></span></li>
</ul>
지역변수 사용하는 방법
<h1>지역 변수 - (th:with)</h1>
<div th:with="first=${users[0]}">
<p>처음 사람의 이름은 <span th:text="${first.username}"></span></p>
</div>
기본객체 = 타임리프에서 기본적으로 제공해준다.
<li>request = <span th:text="${#request}"></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>
편의 객체 = request를 날리때 쿼리 스트링 같은것을 param 이라는 객체를 통해 접근이가능하다.
?paraData=HelloParam 이라는 쿼리형식으로 request 가 날라온 상황
<li>Request Parameter = <span th:text="${param.paramData}"></span></li>
<li>session = <span th:text="${session.sessionData}"></span></li>
<li>spring bean = <span th:text="${@helloBean.hello('Spring!')}"></span></li>
session에 접근도 가능하다.
spring bean에 직접 접근이 가능하다. @helloBean 이라는 @Componet("helloBean)이라 등록된 녀석에게 접근이 가능하다.
자바 8 에서부터 지원하는 LocalDateTime 에도 접근이 가능하다.
Controller 단에서 LocalDateTime.now() 를 model attribute 로 추가해서 보내준 상황이다.
<li>${#temporals.day(localDateTime)} = <span th:text="${#temporals.day(localDateTime)}"></span></li>
<li>${#temporals.month(localDateTime)} = <span th:text="${#temporals.month(localDateTime)}"></span></li>
<li>${#temporals.monthName(localDateTime)} = <span th:text="${#temporals.monthName(localDateTime)}"></span></li>
<li>${#temporals.monthNameShort(localDateTime)} = <span th:text="${#temporals.monthNameShort(localDateTime)}"></span></li>
<li>${#temporals.year(localDateTime)} = <span th:text="${#temporals.year(localDateTime)}"></span></li>
<li>${#temporals.dayOfWeek(localDateTime)} = <span th:text="${#temporals.dayOfWeek(localDateTime)}"></span></li>
<li>${#temporals.dayOfWeekName(localDateTime)} = <span th:text="${#temporals.dayOfWeekName(localDateTime)}"></span></li>
<li>${#temporals.dayOfWeekNameShort(localDateTime)} = <span th:text="${#temporals.dayOfWeekNameShort(localDateTime)}"></span></li>
<li>${#temporals.hour(localDateTime)} = <span th:text="${#temporals.hour(localDateTime)}"></span></li>
<li>${#temporals.minute(localDateTime)} = <span th:text="${#temporals.minute(localDateTime)}"></span></li>
<li>${#temporals.second(localDateTime)} = <span th:text="${#temporals.second(localDateTime)}"></span></li>
<li>${#temporals.nanosecond(localDateTime)} = <span th:text="${#temporals.nanosecond(localDateTime)}"></span></li>
URL 관련
<li><a th:href="@{/hello}">basic url</a></li>
<li><a th:href="@{/hello(param1=${param1}, param2=${param2})}">hello query param</a></li>
<li><a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}">path variable</a></li>
<li><a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}">path variable + query parameter</a></li>
쿼리 파라미터를 날릴떄는 괄호안에 (param1=${param1}, param2=${param2}) 이런식으로 하면되고
경로 변수를 지정 해줄 때는 똑같이 괄호안에 (param1=${param1}, param2=${param2}) 해주면 경로에 해당 변수가 있으면 경로 변수로 알아서 인식한다.
둘이 섞어서 써도 상관이 없다.
리터럴
항상 문자 리터럴은 항상 작은 따옴표로 감싸야한다. 띄우기가 없으면 생략이 가능하지만 띄어쓰기가 있으면 항상 감싸줘야 하나의 문자 리터럴로 인식을 한다.
<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>
리터럴 대체 문법은 용이하다.
조건문
<li>(10 % 2 == 0)? '짝수':'홀수' = <span th:text="(10 % 2 == 0)?'짝수':'홀수'"></span></li>
엘비스 연산자 = 조건문 편하게 쓰기
<li>${data}?: '데이터가 없습니다.' = <span th:text="${data}?: '데이터가없습니다.'"></span></li>
<li>${nullData}?: '데이터가 없습니다.' = <span th:text="${nullData}?:'데이터가 없습니다.'"></span></li>
No operation
<li>${data}?: _ = <span th:text="${data}?: _">데이터가 없습니다.</span></li>
<li>${nullData}?: _ = <span th:text="${nullData}?: _">데이터가없습니다.</span></li>
마치 타임리프가 작동하지 않는 것 처럼 하게 할 수 있다. httml만 그대로 나오게 된다.
attribute = 태그에 클래스 이름 이나 check 관련된것들
<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: 가 발동되서 첫번쨰 속성 추가 같은 경우에는 class="text large" 로 인식이된다.
html 에서는 checkbox type은 속성에 checked 라는 것만 존재해도 저절로 체크박스가 채워져버린다. 이걸 타임리프가 방지해 줄 수 있다.
반복문 + 테이블
<h1>기본 테이블</h1>
<table border="1">
<tr>
<th>username</th>
<th>age</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
</table>
프로퍼티 접근법으로 하나씩 출력해준다.
<h1>반복 상태 유지</h1>
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
<th>etc</th>
</tr>
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">username</td>
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
<td>
index = <span th:text="${userStat.index}"></span>
count = <span th:text="${userStat.count}"></span>
size = <span th:text="${userStat.size}"></span>
even? = <span th:text="${userStat.even}"></span>
odd? = <span th:text="${userStat.odd}"></span>
first? = <span th:text="${userStat.first}"></span>
last? = <span th:text="${userStat.last}"></span>
current = <span th:text="${userStat.current}"></span>
</td>
</tr>
</table>
두번쨰 인자에게 userStat 여러 정보들을 기본적으로 제공해준다. 그것들을 프로퍼티 방식으로 접근하여 렌더링 해 줄 수 있다.
두번째인자는 첫번째 인자 + Stat 으로 저절로 존재하기에 th:each 에서 선언할 때 생략이 가능하다.
조건부 평가문 = 조건 만족안하면 사라짐
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
</tr>
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">1</td>
<td th:text="${user.username}">username</td>
<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>
</tr>
</table>
switch 문
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
</tr>
<tr th:each="user, userStat : ${users}">
<td th:text="${userStat.count}">1</td>
<td th:text="${user.username}">username</td>
<td th:switch="${user.age}">
<span th:case="10">10살</span>
<span th:case="20">20살</span>
<span th:case="*">기타</span>
</td>
</tr>
</table>
block 반복문
<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>
기존의 th:each 문과 달리 div tag 2개를 동시에 반복해준다.
javascript inline
<script th:inline="javascript">
var username = [[${user.username}]];
var age = [[${user.age}]];
//자바스크립트 내추럴 템플릿
var username2 = /*[[${user.username}]]*/ "test username";
//객체
var user = [[${user}]];
</script>
username2 의 경우는 서버에서 렌더링을 거치면 test username 대신 주석처리 된 것이 타임리프를 통해 알맞은 값이 튀어 나온다.
fragment
<footer th:fragment="copy">
푸터 자리 입니다.
</footer>
<footer th:fragment="copyParam (param1, param2)">
<p>파라미터 자리 입니다.</p>
<p th:text="${param1}"></p>
<p th:text="${param2}"></p>
</footer>
<h2>부분 포함 insert</h2>
<div th:insert="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 replace</h2>
<div th:replace="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 단순 표현식</h2>
<div th:replace="template/fragment/footer :: copy"></div>
<h1>파라미터 사용</h1>
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>
insert는 div 안에 footer 를 넣는것이고 replace는 div를 footer 로 바꾸는 것이다.
fragment 에 parameter를 넘기는 것도 가능하다.
템플릿 레이아웃 = 거대한 화면에 개인적인것을 끼워넣는 느낌
<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>
<html xmlns:th="http://www.thymeleaf.org">
<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>
<body>
메인 컨텐츠
</body>
</html>
common_heaer(~{::title})) 을 주게되면 title tag와 그안에있는 데이터가 그냥 통쨰로 들어가게 된다.
그러면 th:replace 에서 완전히 바꿔치기 해버림으로 매번 다르게 렌더링 할 수 있게 된다.
'WEB > Spring MVC 2' 카테고리의 다른 글
Spring MVC 2편 로그인 처리1 쿠키 세션 (0) | 2021.10.10 |
---|---|
Spring MVC 2편 검증2 - Bean Validation (0) | 2021.09.26 |
Spring MVC 2편 검증1 - Validation (0) | 2021.09.05 |
Spring MVC 2편 메시지, 국제화 (0) | 2021.08.21 |
스프링 MVC 2편 - 스프링 통합과 폼 (0) | 2021.08.14 |