타임리프 정리(2/2)

jungnoeun·2022년 9월 19일
0

spring

목록 보기
14/24

타임리프 정리

속성 값 설정

타임리프 태그 속성(Attribute)

th:*

타임리프는 주로 HTML 태그에 th:*속성을 지정하는 방식으로 동작한다. th:*로 속성을 적용하면 기존 속성을 대체한다. 기존 속성이 없으면 새로 만든다.

사용 예)
코드 : <input type="text" name="mock" th:name="userA" />
타임리프 렌더링 후: <input type="text" name="userA" />

속성 추가

th:attrappend : 속성 값의 뒤에 값을 추가한다.
th:attrprepend : 속성 값의 앞에 값을 추가한다.
th:classappend : class 속성에 자연스럽게 추가한다.

사용 예)
코드: <input type="text" class="text" th:attrappend="class=' large'" />
렌더링 후: <input type="text" class="text large" />

checked 처리

<input type="checkbox" name="active" checked="false" />
위와 같이 HTML을 이용하여 checked 속성을 사용하면 checked 속성의 값이 무엇인지와 상관없이 checked 속성이 있다는 것만으로도 체크표시가 되어 화면에 나타난다. 이 불편함을 해결하기 위해서는 타임리프의 th:checked를 사용하면 된다.

타임리프의 th:checked는 값이 false인 경우 checked 속성 자체를 제거한다. 그러면 체크표시가 되지 않은채로 화면에 나타난다.
사용 예)
코드: <input type="checkbox" name="active" th:checked="false" />
타임리프 렌더링 후: <input type="checkbox" name="active" />




반복

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

코드 예시

// java 코드
@GetMapping("/each")
public String each(Model model) {
 addUsers(model);
 return "basic/each";
}
// html코드 일부
<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>

반복 기능

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

  • 반복시 오른쪽 컬렉션(${users})의 값을 하나씩 꺼내서 왼쪽 변수(user)에 담아서 태그를 반복 실행한다.
  • th:eachList뿐만 아니라 배열, java.util.Iterable, java.util.Enumeration 을 구현한 모든 객체를 반복에 사용할 수 있다. Map도 사용할 수 있는데 이 경우 변수에 담기는 값은 Map.Entry이다.

반복 상태 유지

<tr th:each="user, userStat : ${users}">
반복의 두번째 파라미터를 설정해서 반복의 상태를 확인할 수 있다.
두번째 파라미터를 설정해서 반복의 상태를 확인할 수 있다. 두번째 파라미터는 생략가능한데, 생략하면 지정한 변수명(user) + Stat이 된다.
위의 코드에서는 user + Stat = userStat 이므로 생략 가능하다.

반복 상태 유지 기능

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





조건부 평가

타임리프의 조건식
if, unless(if의 반대)

타임리프는 해당조건이 맞지 않으면 태그 자체를 렌더링하지 않는다. 만약 다음 조건이 false인 경우 <span>..<span> 부분 자체가 렌더링되지 않고 사라진다.
<span th:text="'미성년자'" th:if="${user.age lt 20}"></span>

switch
*은 만족하는 조건이 없을 때 사용하는 디폴트이다.
사용 예)

<td th:switch="${user.age}">
 <span th:case="10">10살</span>
 <span th:case="20">20살</span>
 <span th:case="*">기타</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>
/*/-->

결과

<h1>1. 표준 HTML 주석</h1>
<!--
<span th:text="${data}">html data</span>
-->
<h1>2. 타임리프 파서 주석</h1>
<h1>3. 타임리프 프로토타입 주석</h1>
<span>Spring!</span>
  1. 표준 HTML 주석
    자바스크립트의 표준 HTML 주석은 타임리프가 렌더링 하지 않고, 그대로 남겨둔다.
  1. 타임리프 파서 주석
    타임리프 파서 주석은 타임리프의 진짜 주석이다. 렌더링에서 주석 부분을 제거한다.

  2. 타임리프 프로토타입 주석
    타임리프 프로토타입은 약간 특이한데, HTML 주석에 약간의 구문을 더했다.
    HTML 파일을 웹 브라우저에서 그대로 열어보면 HTML 주석이기 때문에 이 부분이 웹 브라우저가 렌더링하지 않지만 타임리프 렌더링을 거치면 이 부분이 정상 렌더링 된다.
    즉, HTML 파일을 그대로 열어보면 주석처리가 되지만, 타임리프를 렌더링 한 경우에만 보이는 기능이다.





블록

th:block은 HTML태그가 아닌 타임리프의 유일한 자체 태그이다.
타임리프의 반복문을 사용할때 반복의 단위가 여러개의 블럭일때 사용한다.

th:block 은 렌더링시 제거된다.

사용 예)

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





자바스크립트 인라인

타임리프는 자바스크립트에서 타임리프를 편리하게 사용할 수 있는 자바스크립트 인라인 기능을 제공한다.
자바스크립트 인라인 기능은 아래와 같이 적용하면 된다.
<script th:inline="javascript">

자바스크립트 인라인 사용전

<script>...</script>안에 자바스크립트를 쓰면 서버에서 동작하는 것이 아니라 html 웹브라우저가 자바스크립트를 실행할때 서버에서는 타임리프 렌더링만 하고 웹브라우저에게 준다. 그러면 웹브라우저에서 age와 같은 변수에 렌더링한 값이 담긴다.

문제1
-> 자바스크립트가 깨지는 문제가 발생한다.
string이면 ""를 다 붙여줘야 한다.
틀림: var username = [[${user.username}]];
고친 것: var username = "[[${user.username}]]";

문제2
내추럴 템플릿을 사용하기 어렵다.
주석처리하면 타임리프가 렌더링해도 값을 사용할 수없다.
-> 인라인사용하면 주석처리된 부분도 사용가능하다.

문제3
객체에 값을 넣을때 값이 제대로 들어가지 않는다.



자바스크립트 인라인 사용 후

타임리프를 자바스크립트에서 잘 사용할 수 있게 도와준다.

  1. 문자가 자바스크립트에서 타입을 알아서 처리해준다.
    -> string이면 알아서 ""같은것들을 추가해준다.
    -> 인라인 사용 후 렌더링 결과를 보면 문자 타입인 경우 " 를 포함해준다. 추가로 자바스크립트에서 문제가 될 수 있는 문자가 포함되어 있으면 이스케이프 처리도 해준다. 예) " \"
  1. 내추럴 템플릿을 처리해준다.
    변수를 할당할때 주석(/*...*/)을 넣어주면 주석안한 부분을 렌더링할때 지우고 주석처리한 부분을 값으로 넣어준다.

예)
var username2 = /*[[${user.username}]]*/ "test username";를 타임리프 렌더링 한 결과
인라인 사용 전 var username2 = /*userA*/ "test username";
인라인 사용 후 var username2 = "userA";

  1. 객체를 json으로 넣어준다.
    객체를 json으로 바꿔서 렌더링해준다. 그러면 자바스크립트에서 json을 그대로 넣을 수 있어서 값을 넣을 수 있다.

var user = [[${user}]]; 를 타임리프 렌더링한 결과:
인라인 사용 전: var user = BasicController.User(username=userA, age=10);
인라인 사용 후: var user = {"username":"userA","age":10};

자바스크립트 인라인 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>





템플릿 조각

웹 페이지를 개발할 때는 공통 영역이 많이 있다. 예를 들어서 상단 영역이나 하단 영역, 좌측 카테고리 등등 여러 페이지에서 함께 사용하는 영역들이 있다. 이런 부분을 코드를 복사해서 여러곳에서 똑같은 코드를 사용한다면 변경시 여러 페이지를 다 수정해야 하므로 상당히 비효율 적이다. 타임리프는 이런 문제를 해결하기 위해 템플릿 조각과 레이아웃 기능을 지원한다.

가져다 쓰는 부분

th:fragment
가져다 쓸 수 있는 템플릿 조각을 의미한다.
아래와 같이 속성값만 정의할 수도 있고, 메서드와 같이 파라미터를 같이 정의할 수 있다.
th:fragment="xxx"
th:fragment="copyParam(param1, param2)"

가지고 와서 쓰기

th:insert

th:insert를 사용하면 현재 태그 내부에 해당 조각을 추가한다.
밑의 예 실행 결과)

<h2>부분 포함 insert</h2>
<div><footer>푸터 자리 입니다.</footer></div>

th:replace

th:replace를 사용하면 현재 태그를 해당 조각으로 대체한다.

<h2>부분 포함 replace</h2>
<footer>푸터 자리 입니다.</footer>

부분 포함시 단순 표현식

~{...} 를 사용하는 것이 원칙이지만 템플릿 조각을 사용하는 코드가 단순하면 이 부분을 생략할 수 있다.

파라미터 사용

<div th:replace="~{template/fragment/footer :: copyParam ('데이터1', '데이터2')}"></ div>
위의 코드와 같이 th:fragment의 속성안에 파라미터를 추가하여, 메서드를 부르는 것과 같이 템플릿 조각을 가져올 수 있다.

<h1>파라미터 사용</h1>
<footer><p>파라미터 자리 입니다.</p>
<p>데이터1</p><p>데이터2</p></footer>

예)

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





템플릿 레이아웃1

템플릿 조각은 일부 코드 조각을 가지고 오는 것이라면, 템플릿 레이아웃은 코드 조각을 레이아웃에 넘겨서 사용하는 방법이다.

즉, 모든 페이지가 공통헤더를 가지고 있는데, 그 헤더에 페이지마다 좀 다른 값을 넣고 싶은 경우, 정보를 문자파라미터를 넘기는 것이 아니라 태그를 넣고 싶은 경우에 해당한다.
정보 대신 태그를 넘기는 것이다.

가져올 부분

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="template/layout/base :: common_header(~{::title},~{::link})">
 <title>메인 타이틀</title>
 <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
 <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>
<body>
메인 컨텐츠
</body>
</html

가지고 와서 사용할 곳

<head th:fragment="common_header(title,links)">
 <title th:replace="${title}">레이아웃 타이틀</title>
 <!-- 공통 -->
 <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}">
 <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
 <script type="text/javascript" th:src="@{/sh/scripts/codebase.js}"></script>
 <!-- 추가 -->
 <th:block th:replace="${links}" />
</head>

태그를 넘기는 쪽에서는
<head th:replace="template/layout/base :: common_header(~{::title},~{::link})">
와 같이 th:replace 와 같이 어떤 작업(insert OR replace)을 할것인지 써주고, th:fragment 속성(common_header)을 써주어서 가지고 있는 태그를 어떤 부분에 줄것인지 적어준다. 그리고 ()사이에 ::태그이름과 같이 써주어서 어떤 태그를 넘길것인지 적어준다.

즉, 1.insert를 할것인지 replace를 할것인지 먼저 적고, 2.태그를 넘길 장소를 적은 th:fragment 속성을 적고, 3. 넘길 태그들을 적어준다.

태그를 받는 쪽에서는
<head th:fragment="common_header(title,links)">
를 적용하여, 가지고 온 태그를 적용할 범위를 정해준다. th:fragment가 있는 블럭이 가지는 범위가 태그를 적용할 수 있는 범위이다. 그리고 나서
<title th:replace="${title}">레이아웃 타이틀</title> 와 같이 1. 작업 내용(insert OR replace)을 적고, 2. ${태그이름}을 사용하여 가지고 온 태그를 사용할 부분을 지정해준다. 그러면 가지고 태그의 값이 적용된다.





템플릿 레이아웃2

템플릿 레이아웃1처럼 헤더부분만 가져올 수도 있지만 html코드 전체를 가지고 올 수 있다.

가지고 와서 사용할 곳

//layoutFile.html
<html th:fragment="layout (title, content)" xmlns:th="http://
www.thymeleaf.org">
<head>
 <title th:replace="${title}">레이아웃 타이틀</title>
</head>
<body>
<h1>레이아웃 H1</h1>
<div th:replace="${content}">
 <p>레이아웃 컨텐츠</p>
</div>
<footer>
 레이아웃 푸터
</footer>
</body>
</html>

태그를 보내는 곳

// layoutExtendMain.html
<!DOCTYPE html>
<html th:replace="~{template/layoutExtend/layoutFile :: layout(~{::title}, ~{::section})}"  xmlns:th="http://www.thymeleaf.org">
<head>
 <title>메인 페이지 타이틀</title>
</head>
<body>
<section>
 <p>메인 페이지 컨텐츠</p>
 <div>메인 페이지 포함 내용</div>
</section>
</body>
</html>

결과

<!DOCTYPE html>
<html>
<head>
<title>메인 페이지 타이틀</title>
</head>
<body>
<h1>레이아웃 H1</h1>
<section>
<p>메인 페이지 컨텐츠</p>
<div>메인 페이지 포함 내용</div>
</section>
<footer>
레이아웃 푸터
</footer>
</body>
</html>

layoutFile.html 을 보면 기본 레이아웃을 가지고 있는데, <html>th:fragment 속성이 정의되어 있다. 이 레이아웃 파일을 기본으로 하고 여기에 필요한 내용을 전달해서 부분부분 변경하는 것으로 이해하면 된다.

layoutExtendMain.html는 현재 페이지인데, <html> 자체를 th:replace 를 사용해서 변경하는 것을 확인할 수 있다. 결국 layoutFile.html 에 필요한 내용을 전달하면서 <html> 자체를layoutFile.html로 변경한다

profile
개발자

0개의 댓글