thymeleaf는 Spring Boot에서 Model에 담은 데이터를 html에 바인딩이 가능하다
바인딩을 위해서는 html 태그안에 thymeleaf 표준 표현식 구문을 입력하여 데이터 바인딩을 할 수 있다.
${...}*{...}#{...}@{...}~{...}문법 작성에 오타가 있는 경우

다음과 같이 브라우저에 오류가 출력된다. 항상 문법 오타에 주의 할 것.
th:texthtml요소에 텍스트를 바인딩 할 때 사용된다.
<p>안녕하세요</p>
예를 들어 다음과 같은 <p>태그에 안녕하세요 부분을 Model에서 가져온 데이터로 출력한다고 가정하자.
먼저 템플릿에서 사용할 데이터를 컨트롤러에서 전달해야한다.
@GetMapping("/test")
public String test(Model model){
model.addAttribute("A", "123"); // Model에 변수 A에 "123"값을 추가
return "articles/test";
}
다음과 같이 컨트롤러에 메소드를 만들고 Model에 템플릿에 사용할 데이터를 넣어줘야 사용이 가능하다.
<p th:text="${A}">안녕하세요</p>
Model에 넣은 데이터를 사용하기 위해 다음과 같이 데이터 바인딩을 해주었다.
이같은 경우는 A변수에 담긴 값이 <p>태그의 텍스트인 안녕하세요를 대체하게 되어 123 값이 출력된다.
Model에 등록한 데이터는 변수이기 때문에 변수 표현식인 ${...} 를 사용했다.
<p>123</p>
브라우저에서는 출력결과로 123이 렌더링되어 출력된다.
th:href<a>태그에 링크를 바인딩 할 때 사용된다.
<a th:href="@{/articles}">링크</a>
링크를 바인딩하기위해 Link URL 표현식@{...} 를 사용했다. 변수를 바인딩 하는게 아니기때문에 Model에서
데이터를 가져올 필요가 없다. 이같은 경우 <a>태그를 클릭하게 되면 /articles경로로 이동되게 된다.
<a href="/articles">링크</a>
브라우저에 렌더링된 결과.
만약 링크에 변수를 바인딩하고 싶을 수도 있다.
<a th:href="@{/articles/{id}(id=${A})}">링크</a>
링크의 변수가 필요한부분을 임의의 이름을 지어 변수이름을 만들고 {}로 감싼후 (id=${A})를 뒤에 추가하여
임의의 변수 id에 값을 넣어줘야한다.
<a href="/articles/123">링크</a>
브라우저에 렌더링된 결과. A의 값이 123이기에 렌더링후 id가 대체되었다.
만약 URL에 여러개의 데이터를 바인딩하고 싶을 수 있다.
<a th:href="@{/articles/{id1}/{id2}(id1=${A}, id2=${B})}">링크</a>
위와 같이 ,으로 구분해서 데이터를 넣어주면 된다.
th:fregment웹페이지를 만들다보면 웹페이지마다 공통된 부분이 존재 할 수 있다. 공통된 부분을 재사용하기 위해 사용 할 수 있다.
<div th:fragment="A">
abc
</div>
위와 같이 사용하면 A라는 이름으로 <div>abc<div> 요소가 fregment화된다. 생성된 fregment는 다른 곳에서 재사용 할 수 있다.
<div th:replace="~{layouts/test :: A}"></div>
생성된 fregment는 th:replace 문법을 통해 요소를 대체 할 수 있으며 재사용이 필요한곳에 사용해주면 된다.
Fragment 표현식~{...}를 사용해야하며 표현식안에 첫번째 부분인 layouts/test부분은 fregment를 등록한 html의 디렉토리 위치를 기입해줘야하며 :: 으로 분리후 뒤에는 사용할 fregment의 이름을 적어줘야한다.
<div>abc</div>
브라우저의 렌더링 결과로 <div> 태그 자체를 대체하여 fregmnet로 대체되었다.
fregment를 사용하는 방법으로 한가지 더있는데 th:insert이다
<div th:insert="~{articles/test :: A}"></div>
th:replace와 사용방법은 동일하지만 <div> 태그가 대체되는것이 아닌 <div>태그의 하위에 fregment가 삽입된다.
<div>
<div>abc</div>
</div>
브라우저에 렌더링 결과로 th:insert를 적용한
th:each여러개의 데이터를 출력하고 싶을때 주로 사용된다.
@GetMapping("/test")
public String test(Model model){
List<Article> articleList = new ArrayList<>(
Arrays.asList(
new Article(1L, "title1", "content1"),
new Article(2L, "title2", "content2"),
new Article(3L, "title3", "content3")
)
);
model.addAttribute("articleList", articleList);
return "articles/test";
}
먼저 컨트롤러에서 템플릿에 사용할 여러개의 데이터를 준비하여 보내준다.
예제에서는 ArrayList인 articleList에 3개의 데이터를 담아 Model에 등록시켜두었다.
public class Article {
private Long id;
private String title;
private String content;
public Article(Long id, String title, String content) {
this.id = id;
this.title = title;
this.content = content;
}
}
예제에서 사용된 Article 클래스는 위와 같은 모습이다.
<div th:each="article : ${articleList}">
<p>id</p>
<p>제목</p>
<p>내용</p>
</div>
th:each로 여러개의 데이터를 가진 List를 출력 할 수 있다. articleList에 담긴 데이터 개수만큼 순회하면서 순서대로 임의의 변수 article에 데이터가 하나씩 들어가게된다. 임의의변수는 이름을 마음대로 해도된다.
<div>
<p>id</p>
<p>제목</p>
<p>내용</p>
</div>
<div>
<p>id</p>
<p>제목</p>
<p>내용</p>
</div>
<div>
<p>id</p>
<p>제목</p>
<p>내용</p>
</div>
브라우저에 렌더링 결과로 articleList에 담긴 3개의 데이터만큼 html 요소가 3번 반복되었다.
하지만 데이터 갯수만큼 요소만 반복되었지 데이터가 바인딩되어있지 않다.
<div th:each="article : ${articleList}">
<p th:text="${article.id}">id</p>
<p th:text="${article.title}">제목</p>
<p th:text="${article.content}">내용</p>
</div>
다음과 같이 데이터 바인딩을 해주게 되면 articleList에서 순서대로 하나씩 article에 데이터가 들어오기때문에 여러개의 데이터를 출력 할 수 있게된다.
<div>
<p>1</p>
<p>title1</p>
<p>content1</p>
</div>
<div>
<p>2</p>
<p>title2</p>
<p>content2</p>
</div>
<div>
<p>3</p>
<p>title3</p>
<p>content3</p>
</div>
브라우저에 렌더링 결과로 articleList의 데이터를 잘 출력한것을 볼 수있다.
th:classappendhtml 태그에 클래스를 추가 할 수 있다.
<p th:classappend="${A}">테스트</p>
예제는 Model에 123값을 가진 A변수가 등록되어있다고 가정한다.
<p class="123">테스트</p>
브라우저에 렌더링 결과로 123이름의 클래스가 등록된 것을 볼 수 있다.
만약 임의의 문자열과 변수를 합칠려면 어떻게 해야할까?
<p th:classappend="|article-${A}|">테스트</p>
예제와 같이 리터럴 대체문법인 | 버티컬바로 감싸준 후 작성하면된다.
<p class="article-123">테스트</p>
브라우저에 렌더링 결과로 다음과 같이 문자열과 변수가 합쳐진모습을 볼 수 있다.
여러개의 클래스를 추가하고 싶다면
<p th:classappend="|article-${A} AAA|">테스트</p>
띄어쓰기로 구분해서 작성하면된다.
<p class="article-123 AAA">테스트</p>
브라우저 렌더링 결과로 article-123클래스와 AAA클래스가 추가되었다.
th:if th:unlessthymeleaf에서 사용 할 수 있는 조건문이다. 조건문이 true인 경우 html요소를 렌더링하고 false이면 렌더링하지 않는다.
@GetMapping("/test")
public String test(Model model){
int a = 1;
model.addAttribute("a", a);
return "articles/test";
}
예제 테스트를 위해 컨트롤러에 a라는 이름의 속성을 추가해두었다.
<div th:if="${a}">a가 존재합니다.</div>
위의 코드는 th:if문법으로 Model에 a라는 속성(Attribute)가 있는지 확인하고 있는 코드이다.
만약 a라는 속성이 Model에 등록되어있다면 <div>a가 존재합니다.</div>가 렌더링되어 브라우저에 나타날 것이고 만약 등록되지 않았다면 브라우저에는 아무것도 렌더링되지 않는다.
<div>a가 존재합니다.</div>
브라우저 렌더링 결과로 Model에 속성 a가 존재하기 때문에 조건문이 true가 되어 렌더링이 성공했다.
<div th:unless="${a}">a가 존재하지 않습니다.</div>
다음은 th:unless문으로 th:if의 부정이다. th:if경우 a속성이 존재하면 true였지만 th:unless의 경우는 a속성이 존재하지않아야 true인 것이다.
<!-- 아무것도 렌더링되지않음 -->
브라우저 렌더링 결과로 Model에 속성 a가 존재하기때문에 false가 되어 아무것도 렌더링되지 않았다.
@GetMapping("/test")
public String test(Model model){
int a = 1;
return "articles/test";
}
th:unless를 더 테스트하기 위해 컨트롤러를 수정하여 Model에 속성 a를 등록하지 않게 수정한다.
<div>a가 존재하지 않습니다.</div>
브라우저 렌더링 결과로 속성 a가 존재하지 않기때문에 조건문이 true가 되어 렌더링에 성공했다.
<div th:if="!${a}">a가 존재하지 않습니다.</div>
th:if에 not연산자인 !를 붙히면 th:unless와 동일한 효과를 낸다. 차이는 없으니 취향껏 방법을 선택하면된다.
<div th:if="${a == 1}">a가 1과 같다</div>
<div th:if="${a > 1}">a가 1보다 크다</div>
<div th:if="${a < 1}">a가 1보다 작다</div>
<div th:unless="${a == 1}">a가 1과 다르다</div>
<div th:if="!${a == 1}">a가 1과 다르다</div>
변수표현식 ${...}안에는 비교연산자 사용도 가능하다.