@GetMapping("/variable")
public String variable(Model model) {
User userA = new User("userA", 10);
User userB = new User("userB", 20);
List<User> list = new ArrayList<User>();
list.add(userA);
list.add(userB);
Map<String, User> map = new HashMap<String, User>();
map.put("userA", userA);
map.put("userB", userB);
model.addAttribute("user", userA);
model.addAttribute("users", list);
model.addAttribute("userMap", map);
return "basic/variable";
}
<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>${userMap['userA'].username} = <span th:text="${userMap['userA'].username}"></span></li>
<li>${userMap['userA']['username']} = <span th:text="${userMap['userA']
['username']}"></span></li>
<li>${userMap['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
1) ${#request}
2) ${#response}
3) ${#session}
4) ${#servletContext}
5) ${#locale}
1) HTTP 요청 파라미터 접근: param
http://localhost:8080/basic/basic-objects?paramData=HelloParam1
<li>Request Parameter = <span th:text="${param.paramData}"></span></li>
Request Parameter = HelloParam1
2) HTTP 세션 접근: session
session.setAttribute("sessionData", "hello session");
<li>session = <span th:text="${session.sessionData}"></span></li>
session = hello session
3) 스프링 빈 접근: @
예) ${@helloBean.hello('Spring!')}
1) 유틸리티 객체 레퍼런스 https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects
2) 유틸리티 객체 레퍼런스 예시
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-b-expression-utility-objects
3) #temporals : 자바8 날짜용 유틸리티 객체
@GetMapping("/date")
public String date(Model model) {
model.addAttribute("localDateTime", LocalDateTime.now());
return "basic/date";
}
<ul>
<li>default = <span th:text="${localDateTime}"></span></li>
<li>yyyy-MM-dd HH:mm:ss = <span th:text="${#temporals.format(localDateTime,
'yyyy-MM-dd HH:mm:ss')}"></span></li>
</ul>
타임리프에서 자바8 날짜인
LocalDate, LocalDateTime, Instant를 사용하려면 추가 라이브러리가 필요하다. 스프링 부트 타임리프를 사용하면 해당 라이브러리가 자동으로 추가되고 통합된다.
thymeleaf-extras-java8time
URL경로에 해당 이름의 {변수명}이 있으면 ()에 있는 변수는 경로변수로 처리, 없으면 ()에 있는 부분은 쿼리 파라미터로 처리
@GetMapping("/link")
public String link(Model model) {
model.addAttribute("param1", "data1");
model.addAttribute("param2", "data2");
return "basic/link";
}
<ul>
<li><a th:href="@{/hello}">basic url</a></li>
// /hello?param1=data1¶m2=data2
<li><a th:href="@{/hello(param1=${param1}, param2=${param2})}">hello query param</a></li>
// /hello/data1/data2
<li><a th:href="@{/hello/{param1}/{param2}(param1=${param1}, param2=${param2})}">path variable</a></li>
// hello/data1?param2=data2
<li><a th:href="@{/hello/{param1}(param1=${param1}, param2=${param2})}">path
variable + query parameter</a></li>
</ul>
| |
내부는 모두 리터럴이 적용된 것으로 보고 변수는 알아서 값을 바꾸어준다. <ul>
<!--주의! 다음 주석을 풀면 예외가 발생함-->
<!-- <li>"hello world!" = <span th:text="hello world!"></span></li>-->
<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>
조건식의 편의 버전 : th:text="${data} ?:
'데이터가없습니다.'"> ${data}에 값이 있으면 출력, 없으면 ㅡ (자바의 삼항연산자와 같은듯)
_ 인 경우 마치 타임리프가 실행되지 않는 것처럼 동작한다. 이것을 잘 사용하면 HTML의 내용 그대로 활용할 수 있다. 마지막 예를 보면 데이터가 없습니다. 부분이 그대로 출력된다. => th:text="${data} ?:
__ " >데이터가 없습니다.<
<input type="text" name="mock" th:name="userA" />
타임리프 렌더링 후
<input type="text" name="userA" />
th:attrappend : 속성 값의 뒤에 값을 추가한다.
th:attrappend = <input type="text" class="text" th:attrappend="class=' large'" /><br/>
렌더링 후
th:attrappend = <input type="text" class="text large"/>
th:attrprepend : 속성 값의 앞에 값을 추가한다.
렌더링 후
<input type="text" class="large text"/>
th:classappend : class 속성에 자연스럽게 추가한다.
<input type="text" class="text" th:classappend="large" />
렌더링 할 때, 알아서 자연스럽게 수정.. 종종 사용한다.
<input type="text" class="text large"/>
th:each
="user, userStat : ${users}"
반복의 두번째 파라미터를 설정해서 반복의 상태를 확인 할 수 있다.
두번째 파라미터는 생략 가능한데, 생략하면 지정한 변수명( user ) + Stat 가 된다
@GetMapping("/each")
public String each(Model model) {
addUsers(model);
return "basic/each";
}
private void addUsers(Model model){
List<User> list = new ArrayList<User>();
User userA = new User("userA", 10);
User userB = new User("userB", 20);
User userC = new User("userC", 30);
list.add(userA);
list.add(userB);
list.add(userC);
model.addAttribute("users", list);
}
<tr th:each="user : ${users}">
<td th:text="${user.username}">name</td>
<td th:text="${user.age}" >age</td>
</tr>
<tr th:each="user, userStat : ${users}">
(userStat를 선언하지 않아도 사용할 수 있다)
<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>
even, odd : 홀수, 짝수 여부 (boolean)
first, last : 처음, 마지막 여부 (boolean)
th:text="'미성년자'" th:if="${user.age lt 20}"
th:text="'미성년자'" th:unless="${user.age ge 20}"
조건이 false 인 경우 해당 부분 자체가 렌더링 되지 않고 통째로 사라진다.
<input type="checkbox" name="active" th:checked="false" />
렌더링 후
<input type="checkbox" name="active" />
이러면 HTML에 checked 속성이 없기 때문에 체크되지 않는다.
<!-- <span th:text="${data}">html data</span> -->
타임리프가 랜더링을 하지 않아서 페이지 소스를 볼 때, 주석 코드가 보임
<!--/*-->
<span th:text="${data}">html data</span>
<!--*/-->
타임리프가 랜더링에서 주석부분을 제거함. 페이지 소스에서도 안 보임
<script th:inline="javascript"> </script>
" "
를 포함해준다.var username = "userA";
var user = {"username":"userA","age":10};
[#
th:each= ....]
[# th:each="user, stat : ${users}"]
var user[[${stat.count}]] = [[${user}]];
(1)/resources/templates/template/fragment/footer.html
<footer th:fragment="copy">
푸터 자리 입니다.
</footer>
(경로 :: fragment의 이름)으로 해당 이름의 fragment내용을 가지고 옴
<h2>부분 포함 insert</h2> -> <div> 안에 fragment내용을 삽입
<div th:insert="~{template/fragment/footer :: copy}"></div>
<h2>부분 포함 replace</h2> -> <div>전체를 fragment내용으로 교체
<div th:replace="~{template/fragment/footer :: copy}"></div>
(2)/resources/templates/template/fragment/footer.html
<footer th:fragment="copyParam (param1, param2)">
<p>파라미터 자리 입니다.</p>
<p th:text="${param1}"></p>
<p th:text="${param2}"></p>
</footer>
=>변수를 frament에서 선언
/resources/templates/template/fragment/fragmentMain.html
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>
=>변수에 들어갈 값은 메인에서 선언
copyParam(데이터1, 데이터2) -> copyParam (param1, param2) ->${param1}, ${param2}로 들어가서 출력
/resources/templates/template/layout/base.html
<head th:fragment="common_header(title,links)">
<title th:replace="${title}">레이아웃 타이틀</title>
<th:block th:replace="${links}" />
/resources/templates/template/layout/layoutMain.html
<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>
(~{::title},~{::link}) : 태그의 전체 내용으로 대체됨
(~{::title},~{::link}) -> common_header(title,links) ->${title}, ${links}
템플릿 조각이랑 똑같은 방식임
common_header(title,links
) 여기서 title, links는 변수명이라서 태그명과 일치하지 않아도 됨
<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>
<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title}, ~{::section})}"