[Thymeleaf] 타임리프
템플릿 엔진 중 하나, html 확장자
태그의 속성을 추가하는 방식
<html xmlns:th="http://www.thymeleaf.org">
표현식
1. 변수식 : ${ }
2. 선택변수식 : *{ } - 객체의 변수 출력
-
product
객체의 변수name
,price
,description
출력
<form method="post" th:object="${product}" name="productForm">
<div>
<label for="name">상품명</label>
<input th:field="*{name}">
</div>
<div>
<label for="price">상품 가격</label>
<input th:field="*{price}">
</div>
<div>
<label for="description">상품 설명</label>
<input th:field="*{description}">
</div>
</form>
3. 메시지식 : #{ } - properties 출력
item.id = 상품ID
item.name = 상품명
<input type="text" th:value="#{item.id}" th:text="#{item.name}" />
4. 링크식 : @{ }
- 파라미터 형식
<a th:href="@{/supply/update(id=${supply.id})}"></a>
<!-- 랜더링 결과 -->
<a th:href="/supply/update?id=1"></a>
- REST 형식
<a th:href="@{/supply/{id}/update(id=${supply.id})}"></a>
<!-- 랜더링 결과 -->
<a th:href="/supply/1/update"></a>
문법 : 태그안에 < th:속성 = “${ }” >
- text : 출력
- if, unless : if-else문
<p th:if="${check}" th:text="${num} + ' : ' + ${trueVal}">true</p>
<p th:unless="${check}" th:text="${num} + ' : ' + ${falseVal}">false</p>
- switch, case : switch-case문
<div th:switch="${num}">
<p th:case="1" th:text="one">1</p>
<p th:case="2" th:text="two">2</p>
<p th:case="*">?</p>
</div>
- each : 반복문
- status : 반복문의 여러 상태를 담고 있는 변수 (index, count, size, current, even, odd, first ,last)
<p th:each="user, status : ${users}" th:text="${status.index} + ' --- ' + ${user.name}"></p>
- with : 변수지정
<p th:with="authType = ${user.authType}+' Type'" th:text="${authType}"></p>
- value : element의 value값 지정
<input type="text" name="writer" title="이름 입력" th:value="${result.wrtier}" />
- block : 임의의 블럭을 지정 ex) div
<th:block th:each="user : ${users}">
<p th:text="${user.login}"></p>
<p th:text="${user.name}"></p>
</th:block>
→ 안의 내용만 남기고 사라짐(브라우저에 랜더링 하지 않음)
숫자형식 - #numbers
<p th:text="${#numbers.formatInteger(1000000, 3, 'COMMA')}"></p> <!-- 1,000,000 -->
<p th:text="${#numbers.formatDecimal(123456.789, 3, 'COMMA', 2, 'POINT')}"></p> <!-- 123,456.79 -->
- #numbers.sequence : 범위내의 연속된 수 생성
<th:block th:each="seq : ${#numbers.sequence(1,3)}">
<p th:text="${seq}"></p>
</th:block>
<!-- 랜더링 결과 -->
<p>1</p>
<p>2</p>
<p>3</p>
문자형식 - #strings
- strings.defaultString : 해당 변수가 null일 때 지정한 문자열 출력
<p th:text="${#strings.defaultString(username, 'unknown')}"></p>
LocalDateTime 날짜형식 - #temporals
dependencies {
compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-java8time', version: '3.0.4.RELEASE'
}
<ul>
<li th:each="dto : ${list}" th:text="${#temporals.format(dto.date,'yyyy-MM-dd')}"></li>
</ul>
<ul>
<li th:text="${#temporals.day(localDateTime)}"></li>
<li th:text="${#temporals.month(localDateTime)}"></li>
<li th:text="${#temporals.monthName(localDateTime)}"></li>
<li th:text="${#temporals.monthNameShort(localDateTime)}"></li>
<li th:text="${#temporals.year(localDateTime)}"></li>
<li th:text="${#temporals.dayOfWeek(localDateTime)}"></li>
<li th:text="${#temporals.dayOfWeekName(localDateTime)}"></li>
<li th:text="${#temporals.dayOfWeekNameShort(localDateTime)}"></li>
<li th:text="${#temporals.hour(localDateTime)}"></li>
<li th:text="${#temporals.minute(localDateTime)}"></li>
<li th:text="${#temporals.second(localDateTime)}"></li>
<li th:text="${#temporals.nanosecond(localDateTime)}"></li>
</ul>
HTTP 기본 객체
<li><span th:text="${#request}"></span></li>
<li><span th:text="${#response}"></span></li>
<li><span th:text="${#session}"></span></li>
<li><span th:text="${#servletContext}"></span></li>
<li><span th:text="${#locale}"></span></li>
Javascript
- 인라인 표기법 사용
[[${변수명}]]
- 스크립트 태그에서 타임리프 태그를 사용하기 위해서는
th:inline="javascript"
를 사용해야 한다 - 자바스크립트로 전달받은 변수는 자동으로
JSON
으로 변환되어 출력된다 -
/*[[${변수명}]]*/ null
: 해당 변수명이 존재하지 않을 경우 null을 출력하도록 설정
<script th:inline="javascript">
let users = "[[${users}]]";
let users2 = /*[[${users2}]]*/ null;
alert(users); // {"id":1, "name":europani}
alert(users2); // null
</script>
Form 관련 문법
1) Form field
- object : 폼에서 사용할 커맨드 객체를 지정
- field : 커맨드 객체의 필드를 사용, input 태그의
id
,name
,value
속성을 자동 처리
@Data
class ProductDTO {
private String name;
private int price;
private String description;
}
@Controller
@RequestMapping("/product/")
class productController {
@GetMapping("/write")
public String test(Model model) {
ProductDTO product = new ProductDTO();
product.setName("티셔츠");
product.setPrice(8900);
product.setDescription("루이까또즈 티셔츠");
model.addAttribute("product", product);
return "product/write";
}
}
<form method="post" th:object="${product}" name="productForm">
<div>
<label for="name">상품명</label>
<input th:field="*{name}">
</div>
<div>
<label for="price">상품 가격</label>
<input th:field="*{price}">
</div>
<div>
<label for="description">상품 설명</label>
<input th:field="*{description}">
</div>
</form>
→ *{name}
= ${product.name}
- 랜더링 결과
<input th:field="*{name}">
→<input id="name" name="name" value="티셔츠">
2) 체크박스
- 처음 랜더링이 되어 체크박스가 체크되지 않은 채 submit 되는 경우
false
가 아니라null
이 전송된다. - 이를 해결하기 위해 스프링 MVC는 타임리프는 hidden을 사용하여
false
로 처리되도록 하게해준다. - 체크박스가 체크되지 않은 경우
name="open"
은 null 이지만name="_open"
이on
(=true)로 전송되어 MVC는 체크되지 않은 것을 판단한다. -
th:field="*{변수명}"
이용하면 타임리프가 알아서 처리해준다.-
히든 필드의 name
은checkbox name
앞에 언더스코어(_)를 추가된 형태로 자동생성 된다 - `체크박스 태그의 id는 필드이름에 시리얼번호가 뒤에 자동으로 붙어 정해진다
-
1) 랜더링 전
<input type="checkbox" th:field="*{open}" />
2) 랜더링 후
<input type="checkbox" id="open1" name="open" value="true" checked="checked">
<input type="hidden" name="_open" value="on"> <!-- 히든 필드 자동생성 -->
멀티 체크박스
- Controller
@ModelAttribute("regions")
private Map<String, String> regions() {
Map<String, String> map = new HashMap<>();
map.put("SEOUL", "서울");
map.put("BUSAN", "부산");
return map;
}
1) 랜더링 전
<div th:each="region : ${regions}">
<input type="checkbox" th:field="*{regions}" th:value="${region.key}">
<label th:for="${#ids.prev('regions')}"th:text="${region.value}"></label>
</div>
-
#ids.prev(String word)
: 파라미터word
뒤에 Id가 1부터으로 부여된다 ex) regions1 -
th:field
와th:value
를 동시에 사용하면 자동으로 두 값을 비교하여checked
설정이 된다
2) 랜더링 후
<div>
<input type="checkbox" id="regions1" name="regions" value="SEOUL">
<input type="hidden" name="_regions" value="on"/>
<label for="regions1">서울</label>
</div>
<div>
<input type="checkbox" id="regions2" name="regions" value="BUSAN">
<input type="hidden" name="_regions" value="on"/>
<label for="regions2">부산</label>
</div>
3) 라디오박스
- 멀티 체크박스와 같다. 히든 필드는 생성되지 않는다
<div th:each="region : ${regions}">
<input type="radio" th:field="*{regions}" th:value="${region.key}">
<label th:for="${#ids.prev('regions')}"th:text="${region.value}"></label>
</div>
4) 셀렉트박스
<select th:field="${dto.region}">
<option value="">지역선택</option>
<option th:each="region : ${regions}" th:value="${region.key}" th:text="${region.value}"></option>
</select>
-
dto.region
: 서버로부터 넘어온 region 값 ex) 서울 -
regions
: 나열될 지역들 ex) 서울, 부산, 대전