탬플릿 중 가장 최선이라는 타임리프
정작 현업에서는 JSP를 사용하는 곳도 아직 많다고 들었지만
JSP는 금방 익힌다고 한다.
개인적으로 Thymeleaf사용하는 곳에 입사하고싶다
text, utext
컨트롤러에서 처리한 파라미터를
${data}라는 형식으로 꺼내 사용할 수 있다.
th:text 태그를 사용하는 경우
<span th:text="${data}"></span>
컨텐츠 안에 직접 출력하는 경우
<li>컨텐츠 안에서 직접 출력하기 = [[${data}]]</li>
< , > 문자를 출력하려하면 HTML태그의 시작,끝 문자와 동일하기 때문에
태그가 아닌 문자로 출력될 수 있도록 ESCAPE라는 것을 자동으로 해준다
오히려 HTML태그를 출력하도록 바꾸고싶다면 UNESCAPE를 하면 되는데
th:utext나
[(${data})]와 같이 입력하면 된다.
SpringEL
앞서 사용했듯 변수를 사용할 때는 ${...}의 형태로 사용한다
또 변수를 표현하는 방법은 여러가지고, list 나 map또한 사용할 수 있다.
//Object ${user.username} = userA ${user['username']} = userA ${user.getUsername()} = userA //List ${users[0].username} = userA ${users[0]['username']} = userA ${users[0].getUsername()} = userA //Map ${userMap['userA'].username} = userA ${userMap['userA']['username']} = userA ${userMap['userA'].getUsername()} = userA |
th:with를 사용해서 지역변수를 선언해서 사용 할 수 있다. 지역변수인 만큼 선언한 태그 안에서만 사용가능하다.
<div th:with="first=${users[0]}">
<p>처음 사람의 이름은 <span th:text="${first.username}"></span></p>
</div>
<h1>식 기본 객체 (Expression Basic Objects)</h1> <ul>
<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>
</ul>
<h1>편의 객체</h1> <ul>
<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>
</ul>
model에 데이터를 넣어서 전송해도 되지만 직접적으로 request, response를 사용 할 수도 있다.
또 직접 파라미터를 간편하게 가져올 수도 있다.(param.paramData)
스프링빈도 사용 가능하다.
url
data1, data2라는 파라미터가 있을때 URL를 작성하는 방법
<h1>URL 링크</h1>
<ul>
<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>
</ul>
/는 경로, /없이 괄호안에 있는 것은 쿼리파라미터로 인식한다.
리터럴
숫자, 문자와 같은 일반 글자
타임리프에서 사용할 때는 작은 따옴표 ' ' 로 감싸야한다.
하지만 중간 공백이 없는 리터럴은 작은따옴표가 없어도 리터럴로 인식해준다.
<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 ' + ${data} = <span th:text="'hello ' + ${data}"></span></li>
<li>리터럴 대체 |hello ${data}| = <span th:text="|hello ${data}|"></span></li>
</ul>
리터럴 문자끼리 + 로 연산을 할 수 있는데, 중간 중간에 데이터가 들어가야하는 경우 매우 귀찮을 수 있다
| | 안에 작성하면 연산자 없이 편하게 이어 쓸 수 있다.
연산
<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 > 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 연산자<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></li>
</ul> </li>
</ul>
기본적으로 자바와 같으나
부등호 사용에서 HTML 엔티티를 사용해야한다.
> (gt), < (lt), >= (ge), <= (le), ! (not), == (eq), != (neq, ne)
|
Elvis연산자는 ?: 모양이 엘비스 프레슬리를 닮아서 지어진 이름이다.
해당 데이터가 있다면 그대로 출력하되 없다면 다음의 내용을 출력한다.
_ 를 출력하는 경우에는 타임리프 태그를 무시하고 HTML의 내용만 출력한다.
반복
<h1>반복</h1>
<tr th:each="user : ${users}">
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
<h1>반복 상태 유지</h1>
<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>
th:each로 반복을 사용할 수 있다. for로 배열요소를 꺼내는 것과 비슷하다
타임리프는 여기에 더해서 반복에 대한 정보도 제공하는데 반복의 두번째 파라미터를 사용해서
index : 0부터 시작하는 값
count : 1부터 시작하는 값 size : 전체 사이즈 even , odd : 홀수, 짝수 여부( boolean ) first , last :처음, 마지막 여부( boolean ) current : 현재 객체 |
위의 정보를 알 수 있다.
두번째 파라미터를 생략할 경우, 첫번째 파라미터와 Stat이 붙은 단어를 자동으로 추가한다.
조건문
<h1>if</h1>
<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>
<h1>switch</h1>
<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>
if문과 switch둘 다 사용 가능하다
해당 조건이 만족하지 않으면 해당 태그 자체가 출력되지 않는다.
주석
1. HTML주석
<!-- -->
그대로 남겨두되 렌더링만 안함(보이긴함)
2. 타임리프 파서 주석
<!--/* */-->
아예 출력안됨(파일을 직접 열면 보임)
3. 타임리프 프로토타입 주석
<!--/*/ /*/-->
파일을 직접 열면 안보이고
타임리프로 렌더링을 해야 보임
블록
div 하나를 기준으로 반복하고싶다면 th:each를 사용하면 되는데
두개의 div를 함께 반복하고 싶을때 사용한다.
<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>
타임리프의 자체태그이며 렌더링하면 보이지않는다.
타임리프에서 javascript
원래 자바스크립트를 사용할 때는 <script>태그를 사용하는데
타임리프와 함께 사용하면 몇가지 문제가 발생할 수 있다.
<!-- 자바스크립트 인라인 사용 전 -->
<script>
var username = [[${user.username}]];
var age = [[${user.age}]];
//자바스크립트 내추럴 템플릿
var username2 = /*[[${user.username}]]*/ "test username";
//객체
var user = [[${user}]];
</script>
<!-- 자바스크립트 인라인 사용 후 -->
<script th:inline="javascript">
var username = [[${user.username}]];
var age = [[${user.age}]];
//자바스크립트 내추럴 템플릿
var username2 = /*[[${user.username}]]*/ "test username";
//객체
var user = [[${user}]];
</script>
<!-- 자바스크립트 인라인 each -->
<script th:inline="javascript">
[# th:each="user, stat : ${users}"]
var user[[${stat.count}]] = [[${user}]];
[/]
</script>
텍스트 변수를 사용하는 경우, 변수에 큰 따옴표 " 를 감싸줘야한다.
따라서 변수마다 사용자가 큰 따옴표를 적어야하는 번거로움이 있는데
타임리프에서 제공하는 자바스크립트 인라인
<script th:inline="javascript">을 사용하면
텍스트 변수마다 알아서 큰 따옴표로 감싸준다
또 렌더링되는 경우에만 나타나는 내추럴 탬플릿도 사용이 가능하며
객체를 출력할때 JSON형식으로 나타내준다.
템플릿 조각, 레이아웃
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<footer th:fragment="copy"> 푸터 자리 입니다.
</footer>
<footer th:fragment="copyParam (param1, param2)">
<p>파라미터 자리 입니다.</p>
<p th:text="${param1}"></p>
<p th:text="${param2}"></p>
</footer>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>부분 포함</h1>
<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>
</body>
</html>
웹페이지에서 공통영역을 만들고 싶은 경우, 각 메이지마다 똑같은 공통영역을 만들기보다
공통영역을 따로 만들고 필요할때 가져오면 더 만들기 편할 것이다.
위 방법을 사용하면 템플릿을 조각으로 사용하는 것 처럼 공통부분 처리를 쉽게 할 수 있다
insert는 위의 경우, div안에 복사할 부분을 집어넣는 것이고
replace는 div를 포함해서 복사할 부분으로 대체한다. 따라서 원래의 div부분에 덧씌워진다.
<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>
<!DOCTYPE html>
<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_header(~{::title},~{::link}) 이 부분이 핵심이다. ::title 은 현재 페이지의 title 태그들을 전달한다.
::link 는 현재 페이지의 link 태그들을 전달한다. 결과를 보자. 메인 타이틀이 전달한 부분으로 교체되었다. 공통 부분은 그대로 유지되고, 추가 부분에 전달한 <link> 들이 포함된 것을 확인할 수 있다. 이 방식은 사실 앞서 배운 코드 조각을 조금 더 적극적으로 사용하는 방식이다. 쉽게 이야기해서 레이아웃 개념을 두고, 그 레이아웃에 필요한 코드 조각을 전달해서 완성하는 것으로 이해하면 된다. |
<!DOCTYPE html>
<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title},~{::section})}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>메인 페이지 타이틀</title> </head>
<body>
<section>
<p>메인 페이지 컨텐츠</p>
<div>메인 페이지 포함 내용</div> </section>
</body>
</html>
<!DOCTYPE html>
<html th:fragment="layout (title, content)" xmlns:th="http://
www.thymeleaf.org">
<head>
<title th:replace="${title}">레이아웃 타이틀</title>
</head>
<body>
<h1>레이아웃 H1</h1>
<div th:replace="${content}">
<p>레이아웃 컨텐츠</p>
</div>
<footer>
레이아웃 푸터
</footer>
</body>
</html>
'개발자일지 > Spring' 카테고리의 다른 글
게시판 만들기 (0) | 2022.03.31 |
---|---|
Spring MVC 2편 - 검증 (Validation) 1 (0) | 2022.03.21 |
Spring MVC 복습 - 간단 게시판 만들기 (0) | 2022.03.15 |
Spring MVC 1편 - MVC 기본기능(응답+) (0) | 2022.03.12 |
Spring MVC 1편 - MVC 기본기능(요청) (0) | 2022.03.11 |