템플릿 엔진 중 하나, 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="*{변수명}" 이용하면 타임리프가 알아서 처리해준다.
    • 히든 필드의 namecheckbox 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:fieldth: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) 서울, 부산, 대전