Thymeleaf 기본 문법 정리✨

byeol·2023년 3월 9일
0

Thymeleaf(타임리프)는 JSP와 같은 템플릿 엔진의 하나이다.
(서버 사이드) 템플릿 엔진은 HTML에 문서에 동적인 데이터가 들어가는 부분이 있을텐데 그걸 좀 더 쉽고 깔끔하게 표현할 수 있도록 돕고 이를 합성하여 출력하는 소프트웨어 또는 소프트웨어 컴포넌트이다.

공부하면서 등장하는 몇 가지 간단한 문법을 정리하고
밑에서부터는 더 심화된 내용을 정리해보려고 한다!

  • 타임리프 사용 선언
<html xmlns:th="http://www.thymeleaf.org">
  • a태그 대신 onclick
onclick="location.href='addForm.html'"
th:onclick="|location.href='@{/basic/items/add}'|"
  • th:text는 태그 안에 있는 내용을 서버에서 받은 데이터로 대체할 때 사용한다.

    <td><a href="item.html" th:href="@{/basic/items/{itemId}
    (itemId=${item.id})}" th:text="${item.id}">회원id</a></td>

    저 회원id 부분에 서버로부터 받은 데이터 item.id를 넣을 것이다.

  • 태그 속성이 아닌 HTML 영역 안에 Model 데이터 넣는 방법[[${}]]

    <li>컨텐츠 안에서 직접 출력하기 = [[${data}]]</li>
  • th:value도 th:text와 같이 모델 데이터를 담고 화면에 뿌릴 때 렌더링

    <input type="text" id="quantity" name="quantity" class="form-control"
              value="10" th:value="${item.quantity}" readonly>
  • th:action 뒤에 URL이 없으면 현재 URL로 데이터를 보낸다.
    th:action은 클라이언트로부터 받은 데이터를 서버로 보내는 역할을 한다.

    <form action="item.html" th:action method="post">
       <div>
         <label for="itemName">상품명</label>
         <input type="text" id="itemName" name="itemName" class="formcontrol"
                placeholder="이름을 입력하세요">
       </div>

    현재 URL은 http://localhost:8080/basic/items/add인데 이것은 GetMapping이고 같은 URL로 가되 PostMapping으로 가게 되어 다른 메서드를 실행한다.

  • 지역변수 선언 th:with
    Model에 users라는 데이터를 담았다고 가정했을 때

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

변수 표현식 ${}

변수 표현식 ${}은 모델에 포함된 값이나 타임리프 변수로 선언한 값을 조회한다.
즉 ${item.id}의 의미는 item.getId()로 프로퍼티 접근법이다.

<!-- 타임리프 변수 itemId의 값을 조회 -->
 <td><a href="item.html" th:href="@{/basic/items/{itemId}
(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
<!-- 프로퍼티 접근법도 사용됨 itemId=${item.id} -->
  • 아래와 같이 List나 Map에 넣은 경우 어떻게 접근하는지 보자
  @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";
    }
  • html 문서를 보면
    <ul>Object
     <li>${user.username} = <span th:text="${user.username}"></span></li>
     <li>${user['username']} = <span th:text="${user['username']}"></span></li>
     <li>${user.getUsername()} = <span th:text="${user.getUsername()}"></span></li>
    </ul>
    <ul>List
     <li>${users[0].username} = <span th:text="${users[0].username}"></span></li>
     <li>${users[0]['username']} = <span th:text="${users[0]['username']}"></span></li>
     <li>${users[0].getUsername()} = <span th:text="${users[0].getUsername()}"></span></li>
    </ul>
    <ul>Map
     <li>${userMap['userA'].username} = <span th:text="${userMap['userA'].username}"></span></li>
     <li>${userMap['userA']['username']} = <span th:text="${userMap['userA']['username']}"></span></li>
     <li>${userMap['userA'].getUsername()} = <span th:text="${userMap['userA'].getUsername()}"></span></li>
    </ul>
    List나 Map에 접근할 때 배열처럼 []를 사용해서 접근한다.

Escape vs. Unescape✨

Model에 "Hello <b>Spring!</b>"을 넣는다는 것은 굵은 글씨로 Spring! 되기를 원한다는 것이다. 그럴려면 HTML은 <b>의 '<'와 '>'를 태그의 시작과 끝으로 인식해야하지만 실제로는 HTML 엔티티에 의해서 '무엇보다 작다'와 '무엇보다 크다'로 변경한다. 이렇게 원래 특수한 문자를 HTML 엔티티로 변경하는 기능을 Escape라고 한다.
th:text,[[...]] 는 Escape 기능을 하기 때문에

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

위와 같이 출력된다.

따라서 Unescape 기능을 하는 th:utext,[(...)]을 사용해야 한다.

<ul>
 <li>th:text = <span th:text="${data}"></span></li>
 <li>th:utext = <span th:utext="${data}"></span></li>
</ul>
<h1><span th:inline="none">[[...]] vs [(...)]</span></h1>
<ul>
 <li><span th:inline="none">[[...]] = </span>[[${data}]]</li>
 <li><span th:inline="none">[(...)] = </span>[(${data})]</li>
</ul>

추가로

  • th:inline="none" 는 [[...]],[(...)]를 타임리프가 해석하지 말라는 뜻 그냥 문자로 보라는 의미이다.

기본 객체들 조회할 때

  • ${#request}, ${#response}, ${#session}, ${#servletContext} : 스프링 부트 3.0부터 제공하지 않는다. -> 그냥 model에 저장해서 불러와야 한다.

  • ${#locale}

  • #어쩌구의 경우 객체 자체가 그대로 제공됨
    예를 들어 #request의 경우 request.getParameter("data")로 해야 데이터 접근이 가능함 request 자체는 HttpServletRequest객체가 그대로 제공된다.

  • 이에 대한 보완으로 편의 객체 제공

    HTTP 요청 파라미터 접근 ${param.paramData}
    HTTP 세션 접근 ${session.sessionData}

    @GetMapping("/basic-objects")
       public String basicObjects(HttpSession session) {
           session.setAttribute("sessionData","Hello Session");
           return "basic/basic-objects";
       }

    스프링 빈 접근 ${@helloBean.hello('Spring!')}

     @Component("helloBean")
       static class HelloBean{
           public String hello(String data){
               return "Hello"+data;
           }
       }

유틸리티 객체 중 날짜

타임리프는 문자, 숫자, 날짜, URI 등을 편리하게 다루기 위한 다양한 유틸리티 객체들을 제공하며 표현식은 #{...}

그 중에서 자바8 날짜 서식을 지원하는 #temporals 유틸리티 객체를 살펴본다.

 @GetMapping("/date")
   public String date(Model model){
       model.addAttribute("localDateTime", LocalDateTime.now());
       return "basic/date";

   }

model에 LocalDataTime.now()로 현재 날짜에 대한 데이터를 저장하여 뷰템플릿에 전달한다.

뷰템플릿에서는 #temporial를 이용해서 이 날짜에 대한 데이터에서 필요한 내용을 뽑아서 사용할 수 있다. (mysql의 date_format처럼)

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

URL @{}

타임리프를 통해서 URL를 넣을 때는

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

a 태그 안에 th:href="@{}"를 사용한다.
또한 타임리프는 쿼리 파라미터나 경로변수를 넣는 방법들을 제공하는데 그 방법에 대해서 알아보자

Controller에서 model에 쿼리파미터나 경로변수가 될 값들을 저장하고 뷰 템플릿에 보내자.

@GetMapping("/link")
    public String link(Model model){
        model.addAttribute("param1","data1");
        model.addAttribute("param2","data2");
        return "basic/link";
    }

여기서 눈여겨 봐야할 문법은 쿼리 파라미터의 선언은 ()이고
경로변수에 대한 선언은 {}임을 기억하자

  • 쿼리 파라미터 thymeleaf 문법

     <li><a th:href="@{/hello(param1=${param1},param2=${param2})}">hello query param</a></li>

    저 URL은 http://localhost:8080/hello?param1=data1&param2=data2이 될 것이다. 쿼리 파라미터를 넣을 때 ?의 역할과 그 경계를 타임리프는 ()를 통해서 나타낸다고 생각하자.

  • 경로 변수에 대한 thymeleaf 문법

     <li><a th:href="@{/hello/{param1}/{param2}(param1=${param1},param2=${param2})}">path variable</a></li>

    URL은 http://localhost:8080/hello/data1/data2이다.
    이상하다 분명 ()를 통해서 쿼리 파라미터를 넣어주었다. 그러나 실제 URL에는 쿼리파라미터가 없다. 그 이유는 경로변수에 선언된 변수(param1, param2)는 쿼리 파라미터로 선언될 수 없기 때문이다. 이 부분을 기억하자!!

    따라서 하나의 예시를 더 보자

    <li><a th:href="@{/hello/{param1}(param1=${param1},param2=${param2})}">path variable + query parameter</a></li>

    URL은 http://localhost:8080/hello/data1?param2=data2이다.
    경로변수에 param2가 없기 때문에 쿼리 파라미터로 param2가 선언되었다.

리터럴

리터럴이란 소스 코드상 고정된 값
Thymeleaf의 리터럴을 표현할 때 문자는 무조건 작은 따옴표 '로 감싸줘야 한다.
그러나 공백 없이 쭉 이어진 문자는 하나의 토근으로 인식할 수 있다.

<!--가능-->
<span th:text="hello">
<!--불가능 : 공백이 있기 때문이다.-->
<span th:text="hello world!"></span>
<!--가능 : 공백이 있기 때문에 '으로 감싸준다.'-->
<span th:text="'hello world!'"></span>

Contoller를 통해서 model에 "data"의 변수에 "Spring!"라는 값을 넣어줬다고 가정한다.

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

보면 th:text="'hello '+${data}" 이 부분을 보자. 문자에 공백이 있어 ''로 감싸주었고 문자와 외부변수를 연결하기 위해서 +를 사용했다. 문법도 어렵고 보기에도 불편하다. 따라서 이를 보완한 리터럴 대체라는 ||라는 문법을 제공한다.
th:text="|hello ${data}|"를 보면 ''와 + 없이 깔끔하게 사용이 가능하다.

연산

타임리프를 이용해서 연산을 할 수 있다.
자바와 같이 사칙연산, %, ? A:B, 비교연산 등의 연산이 가능하다.

먼저 Controller에서 model에 어떤 값을 넣었는지 확인하자.

@GetMapping("/operation")
    public String operation(Model model){
        model.addAttribute("nullData",null);
        model.addAttribute("data","Spring!");
        return "basic/operation";
    }
  • 산술 연산

    <li>10 + 2 = <span th:text="10 + 2"></span></li>
    <li>10 % 2 == 0 = <span th:text="10 % 2 == 0"></span></li>
  • 비교 연산

      <ul>
         <li>1 > 10 = <span th:text="1 &gt; 10"></span></li>
         <li>1 gt 10 = <span th:text="1 gt 10"></span></li>
         <li>1 >= 10 = <span th:text="1 >= 10"></span></li>
         <li>1 ge 10 = <span th:text="1 ge 10"></span></li>
         <li>1 == 10 = <span th:text="1 == 10"></span></li>
         <li>1 != 10 = <span th:text="1 != 10"></span></li>
       </ul>

    모두 가능한 표현이다. true 또는 false로 결과값이 나온다.

  • 조건식
    조건식도 사용이 가능하다.

    <li>(10 % 2 == 0)? '짝수':'홀수' = <span th:text="(10 % 2 == 0)?'짝수':'홀수'"></span></li>
  • Elvis 연산자
    조금 생소한 이름이라서 찾아보았다.

    엘비스 연산자는 ?:로 표현하며, ?:의 왼쪽 객체가 non-null이면 그 객체의 값이 리턴되고, null이라면 ?:의 오른쪽 값을 리턴합니다.

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

  • No-Operation + Elvis 연산자
    자바에 없는 개념이다.
    ""는 마치 타임리프가 실행되지 않은 것처럼 동작한다고 한다.
    Elvis 연산자와 "
    "를 활용해서 어떤 결과가 나오는지 확인해보자

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


    보면 Elvis 연산자에 의해서 데이터가 있는 경우는 왼쪽이 실행된다.
    하지만 데이터가 없는 경우 오른쪽에 있는 _가 실행되어서 마치 타임리프가 없는 것처럼 "데이터가 없습니다"가 출력된다.

기존 속성을 대체하는 th:*

기존 HTML의 속성을 대체하는 타임리프의 th:*에 대해서 알아본다.

  • 그 중에서 기존 HTML 속성 값에 내용을 추가하는 방법

    <h1>속성의 값에 내용을 추가</h1>
     -th:attrappend = <input type="text" class="text" th:attrappend="class='large'"/><br/>
      <!-- 결과 : class="text large"-->
    
     -th:attrprepend = <input type="text" class="text" th:attrprepend="class='large'"/><br/>
      <!-- 결과 : class="large text"-->
     
     -th:classappend = <input type="text" class = "text" th:classappend="large"/><br/>
     <!-- 결과 : class="text large"-->
  • th:checked 속성
    HTML의 checkbox,radio의 경우 checked라는 속성이 선언되면 속성 값이 true인지 false인지 상관없이 기본값으로 체크해버린다.

    따라서 th:checked속성을 이용해서 HTML의 값을 덮어버리나 check유무를 조절할 수 있다.

     - checked o <input  type="checkbox" name="active" th:checked="true" />
     - checked x <input  type="checkbox" name = "active" th:checked="false"/><br/>
     - checked=false  <input type="checkbox" name="active" checked="false" /><br/>
     <!--결과: checked 속성이 false라고 선언되었음에도 불구하고 체크해버린다-->

반복문 th:each

여기서 하나 주의할 것이 있는데 th: each로 하면
An error happened during template parsing이라는 오류가 뜬다.
그러나 th:each 이렇게 공백 없이 작성해야 한다.

먼저 th:each라는 건 많이 보았기 때문에 익숙하지만 반복할 때의 상태를 확인할 수 있는 기능이 있다.

 <tr th:each="user,userStat : ${users}">

위와 같이 반복문의 파라미터를 2개를 설정하면 두 번째 파라미터는 반복의 상태를 알려주는 속성이 된다.

또한 이 두 번째 파라미터를 생략이 가능하고 상태를 확인할 때는 (첫번째 파라미터)+Stat으로 선언하여 사용한다.

<h1>반복 상태 유지</h1>
<table border="1">
  <tr>
    <th>count</th>
    <th>username</th>
    <th>age</th>
    <th>etc</th>
  </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>
    <td>
      index=<span th:text="${userStat.index}"></span>
      count=<span th:text="${userStat.count}"></span>
      size = <span th:text="${userStat.size}"></span>
      even? = <span th:text="${userStat.even}"></span>
      odd? = <span th:text="${userStat.odd}"></span>
      first? = <span th:text="${userStat.first}"></span>
      last? = <span th:text="${userStat.last}"></span>
      current = <span th:text="${userStat.current}"></span>
    </td>
  </tr>
</table>

따라서 위 예시의 두 번째 파라미터 userStat도 생략이 가능하며 사용할 때는 첫번째 파라미터의 명과 Stat를 합쳐서 사용한다.

몇 가지 기능을 확인한다
-count : 0부터 시작
-index: 1부터 시작
-size: 반복 전체 횟수
-even: 저장된 객체의 값이 홀수인가
-odd: 저장된 객체의 값이 짝수인가
-first: 첫 번째 값인가
-last : 마지막 값인가
-current: 현재 객체에 저장된 값

조건문 if,unless,switch

조건에 부합하면 출력하는 것이다.
출력해야할 내용은 th:text에 담긴 것을 조건에 부합하면 출력한다.

<tr th:each="user,userStat : ${users}">
    <td th:text="${userStat.count}">1</td>
    <td th:text="${user.username}">username</td>
    <td>
      <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>
    </td>
</tr>

switch의 경우 java 문법에도 등장하는 switch와 같은 기능을 한다.
마찬가지로 case와 짝궁이다.

<tr th:each="user,userStat : ${users}">
    <td th:text="${userStat.count}">1</td>
    <td th:text="${user.username}">username</td>
    <td th:switch="${user.age}">
      <span th:case="10">10살</span>
      <span th:case="20">20살</span>
      <span th:case="*">기타</span>
    </td>
 </tr>

아무런 case에도 해당되지 않는다라는 의미에서 *를 사용한다.

주석의 종류

  • HTML 주석

    <!--
    <span th:text="${data}">html data</span>
    -->
  • 타임리프 파서 주석 = 타임리프의 진짜 주석= 렌더링 해도 안보임

    <!--/* [[${data}]] */-->
    <!--/*-->
    <span th:text="${data}">html data</span>
    <!--*/-->
  • 타임리프 프로토타입 주석

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

    HTML 파일 자체로 열면 주석처리 되어 보이지 않지만 서버를 통해서 열면 타임리프로 렌더링된다.
    왜 있는 기능인지 잘 모르겠다

결과(개발자도구 f12)

HTML 태그에 종속되지 않는 타임리프의 th:block

타임리프의 자체적인 태그가 있는데 그게 바로 th:block이다.

타임리프가 제공하는 기능들은 HTML 태그 안에 속성으로 들어가게 되는데
그러지 못하는 상황에서는 타임리프의 자체 태그인 th:block을 사용한다.

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

위와 같이 두개의 <div>태그를 묶어줄 HTML의 자체 태그가 존재하지 않아 반복문을 실행할 수 없는 상황에서는 타임리프 자체 태그인 th:block를 만들어서 th:each를 속성으로 넣어주는 것이다.

결과(개발자도구 f12)


보면 타임리프의 자체 태그이기 때문에 개발자 도구를 통해 실제 웹브라우저에 전송된 내용에 th:block가 없음을 확인할 수 있다.

자바스크립트 안에서 타임리프 사용하기 - th:inline

이 내용을 알기 전에 두 가지 개념을 알아야 한다.

<script>태그 : HTML 내부에 자바스크립트와 같은 클라이언트 사이드 스크립트를 정의할 때 사용한다.

내추럴 템플릿(Natural Templete) : 타임리프는 순수 HTML을 유지하는 특성을 가지고 있다. 마치 브라우저에서 타임리프로 만든 html 파일을 파일경로로 오픈해도 html이 잘 나오는 것을 확인할 수 있고, 서버를 통해 뷰 템플릿을 거치면 동적으로 변경된 결과를 확인할 수 있다.
JSP를 포함한 다른 뷰 템플릿들은 해당 파일을 그래도 웹 브라우저에서 열어도 정상적인 HTML 결과를 확인할 수 없다. 오직 서버를 통해 jsp 화면이 렌더링 되고 응답 결과를 받아야 한다.
이렇게 순수 HTML을 그대로 유지하면서 뷰 템플릿으로도 사용할 수 있는 타임리프의 특징을 내추럴 템플릿이라고 한다. 출처: https://chinggin.tistory.com/589

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

타임리프는 적용하기 전과 후를 비교해보자

<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>

렌더링 결과를 보자
var username ="userA"로 선언되어져야 하는데 타임리프의 인라인을 사용하지 않는경우
변수명이 그대로 와버려서 오류가 발생했다.

또한 타임리프의 내추럴 템플릿의 기능은 자바스크립트 인라인 기능을 통해서 사용할 수 있다. 주석을 활용해서 이 기능을 이용할 수 있다.
인라인 적용전에는 주석에 렌더링된 것으로 확인된다.
인라인 적용 후에는 이 주석 부분이 제거되어 렌더링 된 것을 확인할 수 있다.

객체를 가져올 때 인라인 기능을 사용하면 JSON의 형태로 객체를 변환해서 가져온다.

자바스크립트 안에서 th:each 사용하기

 <script th:inline="javascript">
  [# th:each="user,stat:${users}"]
  var user[[${stat.count}]] = [[${user}]]
  [/]
</script>

개발자 도구를 통한 렌더링 결과

신기하다 변수명 자체에도 들어가서 사용이 가능하다니
다음에 꼭 이 기능을 사용하는 서비스를 만들어보고 싶다.

템플릿 조각

말 그대로 템플릿을 조각내서 가져다가 쓰는것
전체적인 흐름은 아래와 같다.
1. th:fragment속성으로 태그 묶음에 이름을 붙여준다.
2. 조각난 템플릿 조각을 가져올 때는 th:inserth:replace를 이용하는데 조각난 템플릿의 경로와 이름을 넣어 가져온다.
3. "~{template/fragment/footer ::copy}"{경로 :: 묶음 이름}

<!-- 조각 1-->
<footer th:fragment="copy">
푸터 자리 입니다.
</footer>

<!-- 조각2 -->
<footer th:fragment="copyParam (param1, param2)">
 <p>파라미터 자리 입니다.</p>
 <p th:text="${param1}"></p>
 <p th:text="${param2}"></p>
</footer>

(참고로 예시의 <footer>태그는 웹페이지의 하단 영역을 표현할 때 사용하는 태그이다.)

<h1>부분 포함</h1>
<h2>부분 포함 insert</h2>
<div th:insert="~{template/fragment/footer ::copy}"></div>

<h2>부분 포함 replace</h2>
<div th:replace="~{template/fragment/footer :: copy}"></div>

<h2>부분 포함 단순 표현식</h2>
<div th:replace="template/fragment/footer :: copy"></div>

<h1>파라미터 사용</h1>
<div th:replace="~{template/fragment/footer :: copyParam ('데이터1','데이터2')}"></div>
  • th:insert는 가져온 템플릿 조각을 <div>태그 안에 넣는 것이고

  • th:replace는 가져온 템플릿 조각이 <div>를 대체한다고 보면 된다.

    또한 쿼리 파라미터처럼 조각 난 템플릿을 불러올 때 쿼리를 넣고 불러올 때 그 값에 렌더링해서 가져온다.

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

결과(개발자 도구 f12)

템플릿 레이아웃

앞서 배운 템플릿 조각은 공통적으로 사용되는 조각들을 나누어서 필요한 곳이 있다면, 곳곳에 사용한 느낌이라면
이번에는 정해진 레이아웃, 그 위치에 태그들을 끼워맞추는 방식으로 진행된다.

이 예시는 <head>태그 자체를 끼워 맞출 것이다.


코드를 보면 저 <head>태그는 template/layout/base 경로에 있는 th:fragment="common_header (title,link)"가 붙은 <head>로 완전히 대체될 것이다.
그러나 대체될 때 현 <head>안에 있는 <title>태그와 <link>태그는 "common_header (title,link)"에 파라미터 형식으로 값을 전달해주고 그 값이 채워진 형태로 대체될 것이다.


이 뭉텅이 자체가 저 위에 있는 html 파일 head로 대체된다. 대체될 때 저 파란색으로 표시된 부분은 파라미터로 선언되어져 있고 앞서 말했듯이

대체될 때 현 <head>안에 있는 <title>태그와 <link>태그는 "common_header (title,link)"에 파라미터 형식으로 값을 전달해주고 그 값이 채워진 형태로 대체될 것이다.

이 부분을 지키며 대체된다.

결과(개발자도구 f12)


앞서 표현한 뭉텅이가 대체되었고 파란색 형광펜 부분도 대체되었다!

비슷하게 <html>태그 자체도 대체할 수 있다!

profile
꾸준하게 Ready, Set, Go!

0개의 댓글