Spring/Spring MVC

ThymeLeaf 공부

민철킹 2021. 5. 13. 19:22

컨트롤러에서 뷰를 호출하고 이를 템플릿 엔진인 thymeleaf를 사용하여 동적으로 변경해보자.

 

컨트롤러

 

정적 리소스(HTML 파일)
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <link href="../css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="max-width: 600px">
    <div class="py-5 text-center">
        <h2>상품 목록</h2>
    </div>
    <div class="row">
        <div class="col">
            <button class="btn btn-primary float-end"
                    onclick="location.href='addForm.html'" type="button">상품
                등록</button>
        </div>
    </div>
    <hr class="my-4">
    <div>
        <table class="table">
            <thead>
            <tr>
                <th>ID</th>
                <th>상품명</th>
                <th>가격</th>
                <th>수량</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td><a href="item.html">1</a></td>
                <td><a href="item.html">테스트 상품1</a></td>
                <td>10000</td>
                <td>10</td>
            </tr>
            <tr>
                <td><a href="item.html">2</a></td>
                <td><a href="item.html">테스트 상품2</a></td>
                <td>20000</td>
                <td>20</td>
            </tr>
            </tbody>
        </table>
    </div>
</div> <!-- /container -->
</body>
</html>

이를 타임리프를 사용하여 동적으로 변경하여보자.


타임리프를 사용하기 위한 th 네임스페이스 추가

xmlns:th="http://www.thymeleaf.org"

 

 

BootStrap 경로 절대경로로 변경

상대 경로로 설정되어 있던 bootstrap파일 경로를 타임리프를 사용하여 절대 경로로 변경하였다.

위와 같이 작성하면 타임리프가 기존에 있던 href를 날리고 th가 붙은 href로 설정함

href="value1" 을 th:href="value2" 의 값으로 변경한다.

타임리프 뷰 템플릿을 거치게 되면 원래 값을 th:xxx 값으로 변경한다.

만약 값이 없다면 새로 생성한다. HTML을 그대로 볼 때는 href 속성이 사용되고, 뷰 템플릿을 거치면 th:href 의 값이 href 로 대체되면서 동적으로 변경할 수 있다.

 

타임리프는 URL 링크를 사용하는 경우 @{...} 를 사용한다. 이것을 URL 링크 표현식이라 한다. URL 링크 표현식을 사용하면 서블릿 컨텍스트를 자동으로 포함한다.

 

상품 등록 버튼 링크 변경

기본 값이 위와 같이 되어 있는데 이 상태에서 버튼을 누르면 현재 html이 있는 폴더 내에서 addForm.html을 찾기 때문에 404가 발생함.

위와 같이 타임리프를 통해 변경하면 /basic/items/add로 링크를 설정하게 된다. 따라서 우리는 해당 경로로 매핑되는 뷰를 만들어주면 됨.(정적 리소스를 갖다주는 것이 아니라)

여기에서는 리터럴 대체 문법이 사용되었다. ==> | ..... |

타임리프에서 문자와 표현식 등은 분리되어 있기 때문에 더해서 사용해야 한다.
<span th:text="'Welcome to our application, ' + ${user.name} + '!'">

리터럴 대체 문법을 사용하면, 더하기 없이 편리하게 사용할 수 있다.
<span th:text="|Welcome to our application, ${user.name}!|">


만들고 싶은 결과 ==> location.href='/basic/items/add'

그냥 사용하면 문자와 표현식을 각각 따로 더해서 사용해야 하므로 다음과 같이 복잡해진다.
th:onclick="'location.href=' + '\'' + @{/basic/items/add} + '\''"

리터럴 대체 문법을 사용하면 편리하게 처리가능
th:onclick="|location.href='@{/basic/items/add}'|"

 

 

실제 상품 목록 출력

정적 리소스에서는  임의로 2개의 상품을 출력하도록 해놓았다.

 

이를 Loop를 돌려 실제 Repository에서 상품을 꺼내오도록 해야한다.

  • th:each를 사용해 모델에 포함된 items가 item변수에 하나씩 담김

모델에는 컨트롤러에서 GET방식으로 /basic/items 로 요청이 들어왔을 때 모든 상품을 리스트에 담고 이 리스트를 모델에 addAttribute를 통해 담아놨다.

 

 

th:text는 태그 안에 들어가는 텍스트 값을 의미한다. 타임리프는 프로퍼티 접근법을 사용하기 때문에 item.id / item.price 등이 가능하다. 태그 안의 텍스트를 item.id로 치환시켜주는 역할을 한다.

  • item.id = item.getId()

 

상품 목록이 정상적으로 출력되는지 확인해보자.

컨트롤러에서 @PostConstruct를 통해 생성자 호출 이후에 넣어 놓은 테스트 상품들이 출력이 된 것을 확인할 수 있다.

 

 

 

상품 링크 변경

위와 같이 정적 리소스로 걸려있는 링크들을 변경

 

  • 경로를 템플릿처럼 편리하게 사용할 수 있음

링크를 /basic/items/해당 상품의 id로 매핑시켜놓았다. 템플릿 문법으로 위와 같이 변수를 사용할 수 있음.

경로 변수 뿐만 아니라 쿼리 파라미터도 생성할 수 있다.

  • ex) th:href="@{/basic/items/{itemId}(itemId=${item.id}, query='test')}"
    • 생성 링크 : http://localhost:8080/basic/items/1?query=test

  • 위와 아래의 href는 동일한 결과를 생성한다. 생성해야할 url이 간단하다면 리터럴 대체 문법을 사용하여 item.id으로 바로 값을 꺼내도 괜찮다.

 

 

 

서버를 실행하고 1번 상품을 클릭해보면

원하는 URL로 이동한 것을 확인할 수 있다. 이또한 매핑되는 뷰를 만들어줘야함.

 

 

타임 리프 = Natural Template

th:xxx 가 붙은 부분은 서버사이드에서 렌더링 되고, 기존 것을 대체한다.

th:xxx 이 없으면 기존 html의 xxx 속성이 그대로 사용된다.

HTML을 파일로 직접 열었을 때, th:xxx 가 있어도 웹 브라우저는 ht: 속성을 알지 못하므로 무시한다. 따라서 HTML을 파일 보기를 유지하면서 템플릿 기능도 할 수 있다.

타임리프는 순수 HTML을 파일을 웹 브라우저에서 열어도 내용을 확인할 수 있고, 서버를 통해 뷰 템플릿을 거치면 동적으로 변경된 결과를 확인할 수 있다. JSP를 생각해보면, JSP 파일은 웹 브라우저에서 그냥 열면 JSP 소스코드와 HTML이 뒤죽박죽 되어서 정상적인 확인이 불가능하다. 오직 서버를 통해서 JSP를 열어야 한다. 이렇게 순수 HTML을 그대로 유지하면서 뷰 템플릿도 사용할 수 있는 타임리프의 특징을 네츄럴 템플릿이라 함.

 

반응형

'Spring > Spring MVC' 카테고리의 다른 글

javax에서 제공하는 @Valid, Spring이 제공하는 BindingResult  (0) 2021.05.22
5/14 공부 내용  (0) 2021.05.14
HTTP Message Converter  (0) 2021.05.11
HTTP Response  (0) 2021.05.10
HTTP Request Message  (0) 2021.05.09