Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

참새의 이야기

[MVC2] Thymeleaf - 기본 본문

Spring

[MVC2] Thymeleaf - 기본

참새짹짹! 2023. 8. 5. 16:01

타임리프는 스프링과의 자연스러운 통합을 지원하는 템플릿 엔진이다.

이번 글에서는 기본적인 사용법을 알아보고, 이후 Form을 만들 때 필요한 기능까지 알아보려 한다.

기본 기능

텍스트

타임리프에서 텍스트를 출력하는 방법으로는 크게 두 가지가 있다.

첫 번째는 th:text 를 사용하는 방법이다.

HTML 태그의 속성으로 추가하면 된다.

아래는 사용 예시이다.

<span th:text="${data}"></span>

HTML 태그가 아닌 문서의 영역에서 출력하고 싶다면 아래와 같이 활용할 수 있다.

[[${data}]]

컨트롤러에서는 model.addAttribute("data", "this is data"); 와 같이 넘겨주면 된다.

escape

HTML에서 사용하는 특수문자가 있다.

<> 같은 경우는 태그로 활용된다.

이런 문자가 텍스트에 포함되어 있다면 개발자의 의도와 다른 출력 결과가 나올 수 있다.

위의 예시에서 data의 값이 <b>Spring!</b> 이고 태그로 인한 볼드 처리를 기대하지 않았을 때, escape 기능을 제공하지 않는다면 출력된 결과는 의도와 달리 볼드 처리된 `Spring!`** 이 될 것이다.**

이를 방지하기 위해 타임리프는 기본적으로 escape 기능을 제공한다.

만약 escape 기능을 사용하고 싶지 않다면 아래와 같은 방법으로 출력할 수 있지만, 필요할 때만 사용하는 것이 좋다.

<span th:utext="${data}"></span>
[(${data})]

변수

타임리프에서의 변수 표현식은 굉장히 간단하다.

${…} 하나로 다양하게 활용할 수 있다.

우선 컨트롤러에서 아래와 같은 로직을 수행한다고 하자.

@GetMapping("/variable")
public String variable(Model model) {
    User userA = new User("userA", 10);
    User userB = new User("userB", 20);

    List<User> list = new ArrayList<>();
    list.add(userA);
    list.add(userB);

    Map<String, User> map = new HashMap<>();
    map.put("userA", userA);
    map.put("userB", userB);

    model.addAttribute("user", userA);
    model.addAttribute("users", list);
    model.addAttribute("userMap", map);

    return "basic/variable";
}

model에는 user, users, 그리고 userMap이라는 attribute가 추가되어 있다.

이들을 ${…} 로 각각 출력하는 것은 물론이고, users나 userMap과 같은 List, Map의 섬세한 출력도 가능하다.

${users[0].username}
${users[0]['username']}
${users[0].getUsername()}

${userMap['userA'].username}
${userMap['userA']['username']}
${userMap['userA'].getUsername()}

지역 변수

선언한 태그 내에서 활용 가능한 지역 변수도 있다.

<div th:with="first=${users[0]}">
 <p>first의 이름은 <span th:text="${first.username}"></span></p>
</div>

th:with 로 선언한 지역 변수 first 를 활용한 예시이다.

유틸리티 객체와 날짜

아래와 같은 유틸리티 객체들이 있으니 외우기보다는 필요할 때 찾아서 활용하는 것이 좋다.

  • #message : 메시지, 국제화 처리
  • #uris : URI 이스케이프 지원
  • #dates : java.util.Date 서식 지원
  • #calendars : java.util.Calendar 서식 지원
  • #temporals : 자바 8 날짜 서식 지원
  • #numbers : 숫자 서식 지원
  • #strings : 문자 관련 편의 기능
  • #objects : 객체 관련 기능 제공
  • #bools : boolean 관련 기능 제공
  • #arrays : 배열 관련 기능 제공
  • #lists , #sets , #maps : 컬렉션 관련 기능 제공
  • #ids : 아이디 처리 관련 기능 제공, 뒤에서 설명

사용 예시

날짜

${localDateTime} 을 출력하면 2023-08-05T12:10:48.173652300 와 같은 형태로 출력된다.

필요에 따라 아래와 같이 포맷을 설정하여 활용하면 된다.

<span th:text="${#temporals.format(localDateTime, 'yyyy-MM-dd HH:mm:ss')}"></span>

URL 링크

url 연결은 @{…} 표현식으로 할 수 있다.

아래와 같이 model의 attribute를 query parameter 혹은 path variable로 활용할 수 있다.

<!--"/hello"-->
<li><a th:href="@{/hello}">basic url</a></li>

<!--"/hello?param1=data1&param2=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>

literal

타임리프에서 문자열은 작은따옴표로 감싸줘야 한다.

th:text=”hello” 와 같이 큰 따옴표로 감싸면 오류가 발생한다.

아래와 같은 리터럴 대체 문법도 있으니 참고하자.

<li>리터럴 대체 |hello ${data}| = <span th:text="|hello ${data}|"></span></li>

연산

산술 연산, 비교 연산

산술 연산은 아래와 같이 할 수 있다.

<span th:text="10 + 2"></span>

비교 연산은 조금 다르다.

비교 연산자를 HTML 엔티티로 바꿔 사용해야 한다.

 

> (gt), < (lt), >= (ge), <= (le), ! (not), == (eq), != (neq, ne)

Elvis 연산자

편의를 위해 제공하는 조건식이다.

null 값을 허용하지 않는 곳에 null 값이 들어오면 기존 조건식의 false에 해당하는 값을 출력한다.

<li>${data}?: '데이터가 없습니다.' = <span th:text="${data}?: '데이터가없습니다.'"></span></li>
<li>${nullData}?: '데이터가 없습니다.' = <span th:text="${nullData}?: '데이터가 없습니다.'"></span></li>

속성 값 설정

타임리프에서는 없는 속성을 추가하거나 이미 존재하는 속성을 대체할 수 있다.

<input type="text" name="mock" th:name="userA" />

위와 같은 경우, 타임리프는 기존 name 인 mock을 userA로 변경한다.

아래의 속성을 이용하여 기존 속성에 값을 추가할 수 있다.

  • th:attrappend
  • th:attrprepend
  • th:classappend

반복

컨트롤러가 model.addAttribute("users", list); 를 실행 후 반환한다고 하자.

list의 user들을 반복문으로 출력하고 싶다면 th:each 를 활용하면 된다.

<tr th:each="user : ${users}">
         <td th:text="${user.username}">username</td>
         <td th:text="${user.age}">0</td>
 </tr>

each는 List 뿐만 아니라, Iterable한 객체들을 모두 반복할 수 있다.

조건부 평가

if, unless

타임리프에서의 조건식은 if와 unless가 대표적이다.

<span th:text="'미성년자'" th:if="${user.age lt 20}"></span>
<span th:text="'미성년자'" th:unless="${user.age ge 20}"></span>

switch

<td th:switch="${user.age}">
         <span th:case="10">10살</span>
         <span th:case="20">20살</span>
         <span th:case="*">기타</span>
 </td>

case가 10도 아니고 20도 아닌 경우, 즉 만족하는 조건이 없을 때 * 의 값을 사용한다.

자바스크립트 인라인

인라인을 사용하지 않으면 텍스트 렌더링 과정에서 변수 이름이 그대로 남아있거나 객체의 toString()이 호출된다.

자바스크립트의 인라인을 th:inline 으로 사용하여, 텍스트를 문자로 출력하거나 객체를 JSON 형식으로 출력할 수 있다.

템플릿 조각

웹에서는 여러 페이지에서 공통적으로 사용하는 영역이 있다.

이런 부분들을 템플릿 조각을 이용한다면 코드의 중복 없이 생성할 수 있다.

insert, replace

<div th:insert="~{template/fragment/footer :: copy}"></div>

div 태그 안에 template/fragment/footer.html 의 copy라는 fragment를 가져와 삽입한다.

replace의 경우 삽입대신 대체한다.

<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></div>

위와 같이 파라미터를 전달할 수도 있다.

reference

이 글은 김영한님의 '스프링 MVC 2편'을 듣고 작성했습니다.

'Spring' 카테고리의 다른 글

[MVC2] 메시지와 국제화  (0) 2023.08.06
[MVC2] Thymeleaf - 스프링 통합과 폼  (0) 2023.08.05
[MVC1] 데이터 담아 Redirect하기  (2) 2023.08.04
[MVC1] HTTP 메시지 컨버터  (0) 2023.08.04
[MVC1] 스프링 MVC Response  (0) 2023.08.04