minOS

타임리프 스프링 통합 - 입력 폼 처리 본문

TIL/김영한의 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술

타임리프 스프링 통합 - 입력 폼 처리

minOE 2024. 8. 30. 14:57
728x90

Thymeleaf 

특징

1) 서버 사이드 HTML 렌더링 (SSR)

타임리프는 백엔드 서버에서 HTML을 동적으로 렌더링 하는 용도로 사용된다.

2) 네츄럴 템플릿
타임리프는 순수 HTML을 최대한 유지하는 특징이 있다. 타임리프로 작성한 파일은 HTML을 유지하기 때문에 웹 브라우저에서 파일을 직접 열어도 내용을 확인할 수 있고, 서버를 통해 뷰 템플릿을 거치면 동적으로 변경된 결과를 확인할 수 있다.  타임리프로 작성된 파일은 해당 파일을 그대로 웹 브라우저에서 열어도 정상적인 HTML 결과를 확인할 수 있다. 물론 이 경우 동적으로 결과가 렌더링 되지는 않는다. 하지만 HTML 마크업 결과가 어떻게 되는지 파일만 열어도 바로 확인할 수 있다. 이렇게 순수 HTML을 그대로 유지하면서 뷰 템플릿도 사용할 수 있는 타임리프의 특징을 네츄럴 템플릿(natural templates)이라 한다.


3)스프링 통합 지원

타임리프는 스프링과 자연스럽게 통합되고, 스프링의 다양한 기능을 편리하게 사용할 수 있게 지원한다. 



기본 표현식
참고
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax

타임리프 템플릿 예시
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>타임리프 예제</title>
</head>
<body>

    <!-- 서버에서 전달된 데이터를 바인딩 -->
    <h1 th:text="${pageTitle}">기본 타이틀</h1>

    <!-- 조건문을 사용한 동적 콘텐츠 -->
    <div th:if="${user.isLoggedIn}">
        <p>안녕하세요, <span th:text="${user.name}">사용자 이름</span>님!</p>
    </div>
    <div th:unless="${user.isLoggedIn}">
        <p>로그인이 필요합니다.</p>
    </div>

    <!-- 반복문을 사용해 리스트 출력 -->
    <ul>
        <li th:each="item : ${items}" th:text="${item}">샘플 아이템</li>
    </ul>

    <!-- 계산된 값 표시 -->
    <p>총 가격: <span th:text="${totalPrice}">0</span>원</p>

</body>
</html>

 

예시 설명:

  1. 데이터 바인딩:
    • <h1 th:text="${pageTitle}">기본 타이틀</h1>: 서버에서 전달된 pageTitle 값을 HTML의 <h1> 태그에 삽입합니다. 만약 pageTitle이 "환영합니다!"라면, 브라우저에서 <h1> 태그 안에 "환영합니다!"가 출력된다.
  2. 조건문:
    • <div th:if="${user.isLoggedIn}">: 사용자가 로그인한 경우에만 이 <div> 블록이 렌더링됩니다. user.isLoggedIn이 true일 때 "안녕하세요, 사용자 이름님!"이라는 문구가 출력된다.
    • <div th:unless="${user.isLoggedIn}">: 사용자가 로그인하지 않은 경우에만 이 <div> 블록이 렌더링되며, "로그인이 필요합니다."라는 문구가 출력된다.
  3. 반복문:
    • <li th:each="item : ${items}" th:text="${item}">: items 리스트의 각 항목이 <li> 태그로 반복 출력된다. 예를 들어, items에 "사과", "바나나", "체리"가 포함되어 있으면 각각의 <li>에 해당 아이템이 표시된다.
  4. 계산된 값 표시:
    • <span th:text="${totalPrice}">: 서버에서 계산된 totalPrice 값을 페이지에 표시한다.

요약:

이 예시는 타임리프의 th: 문법을 사용해 서버에서 전달된 데이터를 HTML에 동적으로 삽입하고, 조건문과 반복문을 통해 복잡한 로직을 HTML 안에 쉽게 통합하는 방법을 보여준다. 이를 통해 웹 페이지가 동적으로 변하는 것을 간단히 구현할 수 있다.

 

타임리프 , 스프링 통합

타임리프(Thymeleaf)는 자바 기반의 템플릿 엔진으로, 주로 HTML 파일을 동적으로 생성하는 데 사용된다. 스프링(Spring)은 자바 플랫폼을 위한 강력한 애플리케이션 프레임워크이다. 이 둘의 통합은 스프링 애플리케이션에서 동적인 웹 페이지를 손쉽게 개발할 수 있도록 해준다.

타임리프와 스프링의 통합은 웹 애플리케이션 개발에서 서버 사이드에서 동적 웹 페이지를 쉽게 생성하고, 데이터를 효율적으로 처리할 수 있게 한다. 스프링 컨트롤러에서 모델 데이터를 타임리프 템플릿에 전달하고, 타임리프는 이 데이터를 바탕으로 HTML 페이지를 동적으로 렌더링한다. 또한, 폼 데이터를 처리하고, 서버와 클라이언트 간의 데이터 바인딩을 간단하게 관리할 수 있어 매우 유용하다.

위의 예시처럼 스프링과의 통합 이전, 타임리프는 독립적으로 HTML 템플릿을 동적으로 생성하는 데 사용되었다.
mvc1 편에서 만든 editform.html 으로 더 자세히 설명하겠다

수정 전 editform.html 
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.min.css}"
          href="../css/bootstrap.min.css" rel="stylesheet">
    <style>
        .container {
            max-width: 560px;
        }
    </style>
</head>
<body>

<div class="container">

    <div class="py-5 text-center">
        <h2>상품 수정 폼</h2>
    </div>

    <form action="item.html" th:action method="post">
        <div>
            <label for="id">상품 ID</label>
            <input type="text" id="id" name="id" class="form-control" value="1" th:value="${item.id}" readonly>
        </div>
        <div>
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}">
        </div>
        <div>
            <label for="price">가격</label>
            <input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}">
        </div>
        <div>
            <label for="quantity">수량</label>
            <input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}">
        </div>

        <hr class="my-4">

        <div class="row">
            <div class="col">
                <button class="w-100 btn btn-primary btn-lg" type="submit">저장</button>
            </div>
            <div class="col">
                <button class="w-100 btn btn-secondary btn-lg"
                        onclick="location.href='item.html'"
                        th:onclick="|location.href='@{/form/items/{itemId}(itemId=${item.id})}'|"
                        type="button">취소</button>
            </div>
        </div>

    </form>

</div> <!-- /container -->
</body>
</html>​

1) HTML 템플릿의 가독성 유지: 타임리프는 th: 속성을 사용하여 HTML 구조를 그대로 유지하면서 동적인 값을 주입할 수 있게 한다. 이는 HTML 파일을 브라우저에서 직접 열어볼 때도 자연스러운 형태를 유지하게 해준다.

2) 서버 사이드 데이터 바인딩: th:value 속성을 통해 서버에서 전달된 데이터를 HTML 폼 필드에 바인딩할 수 있다. 예를 들어, 상품 수정 폼에서 각 필드에 해당하는 값을 서버에서 가져와 입력된 상태로 렌더링한다.

3) 동적인 동작 처리: th:onclick과 같은 속성을 사용하여 자바스크립트 이벤트에 동적으로 URL을 바인딩할 수 있다. 이로써 서버에서 생성된 데이터를 바탕으로 클라이언트 사이드에서 동적으로 동작을 처리할 수 있게 된다.

4) 스프링과의 연계: 스프링 컨트롤러에서 모델 데이터를 전달받아, 타임리프 템플릿에서 이를 사용해 동적인 페이지를 생성할 수 있다. 이때 각 필드의 값은 스프링 모델 객체에서 가져오며, 이를 통해 양방향 데이터 바인딩이 가능해진다.


스프링 통합 후 editform.html 
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.min.css}"
          href="../css/bootstrap.min.css" rel="stylesheet">
    <style>
        .container {
            max-width: 560px;
        }
    </style>
</head>
<body>

<div class="container">

    <div class="py-5 text-center">
        <h2>상품 수정 폼</h2>
    </div>

    <form action="item.html" th:action th:object="${item}" method="post">
        <div>
            <label for="id">상품 ID</label>
            <input type="text" id="id" class="form-control" th:field="*{id}" readonly>
        </div>
        <div>
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" name="itemName" class="form-control" th:field="*{itemName}">
        </div>
        <div>
            <label for="price">가격</label>
            <input type="text" id="price" class="form-control" th:field="*{price}">
        </div>
        <div>
            <label for="quantity">수량</label>
            <input type="text" id="quantity" class="form-control" th:field="*{quantity}">
        </div>

        <hr class="my-4">

        <div class="row">
            <div class="col">
                <button class="w-100 btn btn-primary btn-lg" type="submit">저장</button>
            </div>
            <div class="col">
                <button class="w-100 btn btn-secondary btn-lg"
                        onclick="location.href='item.html'"
                        th:onclick="|location.href='@{/form/items/{itemId}(itemId=${item.id})}'|"
                        type="button">취소</button>
            </div>
        </div>

    </form>

</div> <!-- /container -->
</body>
</html>​


수정 전과 수정 후의 타임리프 템플릿을 비교하면, 스프링과 타임리프의 통합이 어떻게 향상되었는지 명확히 알 수 있다. 이 비교를 통해 스프링 통합의 장점을 설명할 수 있다.


수정 전 타임리프 템플릿:

데이터 바인딩 방식: 수정 전에는 각 폼 필드에 대해 th:value 속성을 사용하여 개별적으로 데이터를 바인딩했다. 즉, HTML의 <input> 태그마다 th:value 속성을 지정하여 모델에서 전달된 데이터를 해당 필드에 바인딩했다.

<input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}">

폼 객체 바인딩 없음: 전체 폼을 특정 객체에 바인딩하지 않고, 개별 필드마다 바인딩을 처리한다. 이는 필드가 많아질수록 코드가 길어지고 복잡해질 수 있다.

수정 후 타임리프 템플릿:

폼 객체 바인딩: 수정 후에는 th:object 속성을 사용하여 폼 전체를 특정 모델 객체(item)에 바인딩했다. 이로 인해 각 필드는 th:field 속성을 통해 해당 객체의 필드와 자동으로 연결된다.

<form action="item.html" th:action th:object="${item}" method="post">
    <input type="text" id="itemName" class="form-control" th:field="*{itemName}">
</form>

여기서 th:object="${item}"는 폼 전체를 item 객체와 연결하고, th:field="*{itemName}"는 item 객체의 itemName 필드와 자동으로 연결되어 데이터를 바인딩한다.

데이터 바인딩 간소화
: th:field를 사용해 각 필드가 자동으로 해당 객체의 속성과 연결되므로, 코드가 훨씬 간결해지고 유지보수가 쉬워집니다. 추가적인 입력 필드가 필요할 때도 일관된 방식으로 필드를 추가할 수 있다.

 

타임리프와 스프링 통합의 장점

스프링 통합의 장점

데이터 바인딩 자동화: th:object와 th:field를 사용하여 스프링 모델 객체와 폼 데이터 간의 바인딩을 자동으로 처리. 코드의 일관성을 높이고, 필드 간 중복을 줄이며 폼 처리를 간소화.

유지보수 용이성: 폼이 모델 객체에 바인딩되어 있어, 추가 필드나 변경 사항이 발생할 때 코드 수정이 용이. 더 적은 코드로 더 많은 작업을 처리할 수 있어 유지보수가 훨씬 쉬워짐.

템플릿 가독성 향상: th:field를 사용해 HTML 구조를 더욱 직관적으로 유지할 수 있어, 코드 가독성이 높아짐. 팀 작업이나 코드 리뷰 시에도 이점을 제공.

강력한 스프링 연계: 스프링과의 강력한 통합 덕분에 폼 데이터 처리와 유효성 검사가 자연스럽게 이루어짐. 스프링 MVC와 타임리프의 시너지를 통해 더욱 견고한 웹 애플리케이션을 구현 가능.

요약
스프링과 타임리프의 통합으로 폼 데이터 바인딩이 간결해지고, 유지보수성이 향상되며, 템플릿 가독성이 높아짐. 이러한 통합은 스프링 애플리케이션에서 동적인 웹 페이지를 더욱 효율적으로 관리할 수 있게 함.

 

728x90