Thymeleaf -3

이정원·2024년 10월 30일
post-thumbnail

9.반복

타임리프에서 반복은 th:each를 사용한다. 추가로 반복에서 사용할 수 있는 여러 상태 값을 지원한다.

컨트롤러

@GetMapping("/each")
 public String each(Model model) {
 addUsers(model);
 return "basic/each";
 }
 private void addUsers(Model model) {
    List<User> list = new ArrayList<>();
    list.add(new User("userA", 10));
    list.add(new User("userB", 20));
    list.add(new User("userC", 30));
    model.addAttribute("users", list);
 }

템플릿 코드

<tr th:each="user : ${users}">
     <td th:text="${user.username}">username</td>
     <td th:text="${user.age}">0</td>
</tr>
<tr th:each="user, userStat : ${users}">
        <td th:text="${userStat.count}">username</td>
        <td th:text="${user.username}">username</td>
        <td th:text="${user.age}">0</td>
이하 생략

동작 설명: 컨트롤러에서 User 클래스 인스턴스들을 담은 list를 model에 users란 명칭으로 추가하고 템플릿에 넘겨주면,

1.tr(테이블의 행)에 th:each는 users 리스트를 반복(iteration)하면서 각 요소를 user 변수에 할당한다.
2.td(각 셀)에 프로퍼티 접근 으로 데이터를 할당한다.

자료구조(컬렉션)은 List 뿐만 아니라 배열, java.util.Iterable, java.util.Enumeration 을 구현한 모든 객체를 반복에 사용할 수 있다. Map도 사용할 수 있는데 이 경우 변수에 담기는 값은 Map.Entry 이다.

th:each="변수명, 상태변수명 ": ${model이름} 형식으로 작성하며, 첫번째는 컬렉션에 대한 인스턴스를 하나씩 가져오고, 두번째는 현재 루프에 대한 상태를 나타낸다.

반복 상태 속성(th:each 두번째 인자)

  • index : 0부터 시작하는 값
  • count : 1부터 시작하는 값
  • size : 전체 사이즈
  • even , odd : 홀수, 짝수 여부(boolean )
  • first , last :처음, 마지막 여부(boolean)
  • current : 현재 객체

10.조건부 평가

타임리프의 조건식:if , unless ( if 의 반대)
th:if=${해당 위치에 문자열에 대한 논리 연산이 충족해야 태그가 렌더링된다.}

컨트롤러

@GetMapping("/condition")
 public String condition(Model model) {
 addUsers(model);
 return "basic/condition";
 }

템플릿 코드

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

HTML 원본 페이지

해당 인스턴스의 age가 span "'미성년자'" 조건에 맞지 않아 span 태그가 렌더링되지 않았다.

11.주석

주석 형식

1.HTML 주석

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

2.타임리프 파서 주석

 <!--/* [[${data}]] */-->

3.타임리프 프로토타입 주석

 <!--/*/<span th:text="${data}">html data</span>/*/-->

타임 리프는 HTML 주석 안에 타임리프 문법이 있더라도 렌더링 하지 않는다. 타임 리프 프로토 타입 주석은 파일 자체를 웹 브라우져에서 렌더링하지 않지만 웹 어플리케이션 실행시 타임 리프가 구동이 되며 렌더링된다.

템플릿 코드

<span th:text="${data}">html data</span>
<h1>1. 표준 HTML 주석</h1>
<!--<span th:text="${data}">html data</span>-->
<h1>2. 타임리프 파서 주석</h1>
<!--/* [[${data}]] */-->
<!--/*-->
<span th:text="${data}">html data</span>
<!--*/-->
<h1>3. 타임리프 프로토타입 주석</h1>
<!--/*/
<span th:text="${data}">html data</span>
/*/-->

HTML 원본 페이지

12. 블록

th:block는 HTML에 직접 영향을 미치지 않으면서 타임리프에서 반복문이나 조건문을 사용해 여러 요소를 그룹으로 처리할 수 있는 타임리프 유일한 태그 이다.

템플릿 코드

<th:block th:each="user : ${users}">
    <div>
        사용자 이름1 <span th:text="${user.username}"></span>
        사용자 나이1 <span th:text="${user.age}"></span>
    </div>
    <div>
        요약 <span th:text="${user.username} + ' / ' + ${user.age}"></span>
    </div>
</th:block>

단순 span으로 반복문을 처리한다면 HTML에 불필요한 태그가 렌더링되어 HTML 구조에 영향을 줄수 있다. 특히 블록(th:block)은 타임리프의 조건문(th:if), 반복문(th:each) 등과 조합에 유용하다.

HTML 원본 페이지

<th:block th:each> 문이 사라진것을 볼수 있다.

13. 자바 스크립트 인라인

자바스크립트에서 타임리프를 편리하게 사용할수 있는 인라인 기능을 타임리프가 제공한다.

 <script th:inline="javascript">

템플릿 코드

<!-- 자바스크립트 인라인 사용 전 -->
<script>
    var username = [[${user.username}]];
    var age = [[${user.age}]];

    //자바스크립트 내추럴 템플릿
    var username2 = /*[[${user.username}]]*/ "test username";
    //객체
    var user = [[${user}]];
 </script>
<!-- 자바스크립트 인라인 사용 후 -->
<script th:inline="javascript">
    var username = [[${user.username}]];
    var age = [[${user.age}]];
    //자바스크립트 내추럴 템플릿
    var username2 = /*[[${user.username}]]*/ "test username";
    //객체
    var user = [[${user}]];
 </script>

HTML 원본 페이지

여기서 자바스크립트 인라인을 사용하지 않는다면 문법이 깨져 오류가 발생한다. 이와같이 자바스크립트에 타임리프 값들을 전달하기 쉽지 않다.

또한 Java 객체를 javascript 변수에 할당한다면 to_string 함수가 호출되어 var user = BasicController.User(username=userA, age=10); 이렇게 그대로 들어가버린다.

따라서 th:inline="javascript"를 사용한다면 이 영역은 자바스크립트 영역이고, 타임리프가 다음과 같은 편의 기능을 제공한다.

  • 문자열 자동 감싸기: 타임리프가 문자열 값에 자동으로 "을 추가하여 올바른 자바스크립트 구문을 유지한다. 특수 문자도 자동으로 이스케이프 처리되어 문자열 내에서 안전하게 사용된다.

    자동 이스케이프: 큰따옴표 ("): \" ,작은따옴표 ('): \' , 백슬래시 (): \ ,줄바꿈 (\n) 및 캐리지 리턴 (\r): \n, \r

  • 주석 내 값 사용: 타임리프 변수를 주석(/[[ ]]/) 안에 넣으면, 타임리프가 처리해 주석 내의 값이 출력된다. 기본 값이나 테스트 데이터를 사용해 코드를 확인할 때 유용하다.
  • Java 객체 직렬화: Java 객체를 JSON 형식으로 직렬화하여 JavaScript 변수에 할당할 수 있어 편리하다.

또한 javascripts 인라인은 each를 지원한다.

<!-- 자바스크립트 인라인 each -->
 <script th:inline="javascript">
[# th:each="user, stat : ${users}"]
 var user[[${stat.count}]] = [[${user}]];
 [/]
 </script>

결과

<script>
 var user1 = {"username":"userA","age":10};
 var user2 = {"username":"userB","age":20};
 var user3 = {"username":"userC","age":30};
 </script>

Thymeleaf -4에 계속 ..

0개의 댓글