리터럴
리터럴은 소스 코드상에 고정된값을 말하는 용어이다.
예시를 보면 hello는 소문자가 연속된 문자이므로 작음 따옴표를 생략할 수 있다.
리터럴 테스트
컨트롤러
@GetMapping("/literal")
public String literal(Model model) {
model.addAttribute("data", "Spring!");
return "basic/literal";
}
뷰 템플릿
<li>'hello' + ' world!' = <span th:text="'hello' + ' world!'"></span></li>
<li>'hello world!' = <span th:text="'hello world!'"></span></li>
<li>'hello ' + ${data} = <span th:text="'hello ' + ${data}"></span></li>
<li>리터럴 대체 |hello ${data}| = <span th:text="|hello ${data}|"></span></li>
리터럴 끼리 더하는연산도 가능하고, 리터럴과 변수를 더하는것도 가능하다.
마지막에 리터럴 대체문자를 이용해서, 합치는 예시인데 작은 따음표도 필요없고, 공백도 넣어도되고, 변수와 합쳐도된다.
리터럴 문자를 써야한다하면 리터럴대체를 사용하는것을 생각하자.
결과
연산
타임리프 연산은 자바와 크게 다르지 않다.
HTML안에서 사용하기 때문에 HTML 엔티티를 사용하는 부분만 주의하자.
( <, > 와 같은 태그로 사용되는 기호들이 HTML 엔티티라는 다른 기호로 바뀌는것을 의미한다.)
연산 테스트
컨트롤러
@GetMapping("/operation")
public String operation(Model model) {
model.addAttribute("nullData", null);
model.addAttribute("data", "Spring!");
return "basic/operation";
}
뷰 템플릿
<li>산술 연산
<ul>
<li>10 + 2 = <span th:text="10 + 2"></span></li>
<li>10 % 2 == 0 = <span th:text="10 % 2 == 0"></span></li>
</ul>
</li>
<li>비교 연산
<ul>
<li>1 > 10 = <span th:text="1 > 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>
</li>
<li>조건식
<ul>
<li>(10 % 2 == 0)? '짝수':'홀수' = <span th:text="(10 % 2 == 0)?'짝수':'홀수'"></span></li>
</ul>
</li>
<li>Elvis 연산자
<ul>
<li>${data}?: '데이터가 없습니다.' = <span th:text="${data}?: '데이터가없습니다.'"></span></li>
<li>${nullData}?: '데이터가 없습니다.' = <span th:text="${nullData}?:'데이터가 없습니다.'"></span></li>
</ul>
</li>
<li>No-Operation
<ul>
<li>${data}?: _ = <span th:text="${data}?: _">데이터가 없습니다.</span></li>
<li>${nullData}?: _ = <span th:text="${nullData}?: _">데이터가없습니다.</span></li>
</ul>
</li>
비교연산은 Http엔티티로 넣어줘야한다 &를 붙이지 않아도 동작한다.
조건식은 자바의 삼항연산자과 비슷하다.
Elvis 연산자는 ${변수}에 데이터가 있으면 변수를 출력하고, 없으면 : 뒤에 적힌것을 출력한다. (조건식느낌)
No-operation은 말그대로 연산을 진행하지않는다는것이다.
Elvis연산처럼 생겼는데 : 뒤에 _가 있다.
만약 데이터가 없어서 _가 선택됬다면 해당 태그는 타임리프를 적용하지않고, 기본값을 출력하게된다.
nullData는 null이니까 _가 선택될것이고 -> 타임리프 동작 x -> 기본출력인 "데이터가 없습니다."가 출력된다
_를 no operation이라고 한다
뷰 결과
속성값 설정
타임리프는 주로 HTML 태그에 th:* 속성을 지정하는 방식으로 동작한다.
th:* 로 속성을 적용하면 기존 속성을 대체한다. 기존 속성이 없으면 새로 만든다.
이미 html속성으로 name이라는것이 존재하고, th:name이라는 속성도 존재할때
렌더링시 name의 속성값을 th:name의 속성값으로 치환해버린다.
테스트
컨트롤러
@GetMapping("/attribute")
public String attribute() {
return "basic/attribute";
}
뷰 템플릿
<body>
<h1>속성 설정</h1>
<input type="text" name="mock" th:name="userA" />
<h1>속성 추가</h1>
- th:attrappend = <input type="text" class="text" th:attrappend="class='large'" /><br/>
- th:attrprepend = <input type="text" class="text" th:attrprepend="class='large'" /><br/>
- th:classappend = <input type="text" class="text" th:classappend="large" / ><br/>
<h1>checked 처리</h1>
- checked o <input type="checkbox" name="active" th:checked="true" /><br/>
- checked x <input type="checkbox" name="active" th:checked="false" /><br/>
- checked=false <input type="checkbox" name="active" checked="false" /><br/>
</body>
<input type="text" name="mock" th:name="userA" />
이 부분은 name="mock"이 th:name이 존재하므로 userA라는 값으로 치환될것이다.
결과웹페이지에서 소스보기를 하면 확인할 수 있다.
- th:attrappend = <input type="text" class="text" th:attrappend="class='large'" /><br/>
- th:attrprepend = <input type="text" class="text" th:attrprepend="class='large'" /><br/>
- th:classappend = <input type="text" class="text" th:classappend="large" / ><br/>
attrappend는 속성 값뒤에 값을 추가한다. 코드를 보면 class라는 속성에 large를 뒤에 붙인다는 뜻
즉 textlarge가 될것이다.
attrprepend는 앞에 붙인다는뜻
classappend는 자연스럽게 추가한다는 뜻이다.
<h1>checked 처리</h1>
- checked o <input type="checkbox" name="active" th:checked="true" /><br/>
- checked x <input type="checkbox" name="active" th:checked="false" /><br/>
- checked=false <input type="checkbox" name="active" checked="false" /><br/>
html은 checked라는 속성이 있기만 하면 체크된 상태로 보여준다.
마지막코드에 checked="false"가 되어있지만 checked라는 속성이 있기때문에 체크된 상태로 보여준다.
그래서 타임리프의 th:checked를 이용했을때 만약 th:checked="false"라면 checked라는 속성 자체를 지워버린다.
- checked o <input type="checkbox" name="active" th:checked="true" /><br/>
- checked x <input type="checkbox" name="active" th:checked="false" /><br/>
아래의 경우 th:checked 가 false이므로 th:checked가 없어진다.
만약에 일반속성으로도 checked가 들어가있고 th:checked도 들어가있는데 th:checked 가 false이면?
이또한 결과가 같다. 그냥 checked라는 속성을 다 지운다.
만약 파일로 열었을때
- checked o <input type="checkbox" name="active" th:checked="true" /><br/>
- checked x <input type="checkbox" name="active" th:checked="false" /><br/>
- checked=false <input type="checkbox" name="active" checked="false" /><br/>
첫번쨰 두번쨰줄은 checked라는 속성이 없다. th가 붙은 속성들은 파일로 열때 html이 뭔지 몰라서 취급안한다.
그래서 checked가 있는 마지막줄에만 체크가 된다.
일반 속성과 th 속성이 같다면 서버를 통해서 뷰 렌더링할때는 th속성으로 치환될것이고
그게 아니라 파일로 열기해서 html로 실행시킨다면 th관련 속성은 무시되고 일반속성이 동작한다.
반복
타임리프에서 반복은 th:each 를 사용한다.
추가로 반복에서 사용할 수 있는 여러 상태 값을 지원한다.
반복 테스트
컨트롤러
@GetMapping("/each")
public String each(Model model) {
addUsers(model);
return "basic/each";
}
private void addUsers(Model model) {
List<Object> 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);
}
모델에 리스트 데이터를 넣는다.
뷰 템플릿
<h1>기본 테이블</h1>
<table border="1">
<tr>
<th>username</th>
<th>age</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
보면 th:each를 통해 리스트에 값을 하나씩 user로 받아오고
그 밑에서 user.username 으로 접근연산자(.)을 이용해서 변수값을 사용하는 모습이다.
소스를 보면
th:each 의 반복때문에
<tr>
<td th:text="${user.username}">username</td>
<td th:text="${user.age}">0</td>
</tr>
이런 구조가 3개가 더 생겼다.
반복 테스트2
반복의 두번째 파라미터를 이용하여 반복의 상태를 확인 할 수 있다.
전체 뷰 템플릿
<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>
<tr th:each="user, userStat : ${users}">
이 부분을보면 users에서 user말고 userStat도 받는것을 확인할 수 있는데
두번째 파라미터를 적게되면 그 변수에 반복의 상태에 대한 값이 저장된다.
두번째 파라미터를 스킵하면 첫번쨰변수 + Stat이라는 변수로 알아서 저장된다( 위같은경우는 user + Stat )
반복의 상태에 대한값은 무엇이 있을까.
결과 모습
even과 odd의 여부는 count에서 체크한다.
조건부 평가 (if, unless)
타임리프의 조건식
if , unless ( if 의 반대)
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
</tr>
<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>
</table>
lt, ge는 Http엔티티이다. &가 없어도 동작한다!
if와 unless의 조건이 맞지않으면 해당 속성이 있는 태그자체가 사라지고 렌더링이 된다.
<span th:text="'미성년자'" th:if="${user.age lt 20}"></span>
이 부분을 보면 if(user.age < 20 ) 와 같고 age가 20보다 아래인경우 해당 span태그의 내용이 사라진다.
<span th:text="'미성년자'" th:unless="${user.age ge 20}"></span>
unless (user.age >= 20) 과 같고 unless는 if와 반대이므로 이 조건과 맞지않을때 동작한다.
age가 20보다 작다면 동작하고 20과 같거나 크다면 해당 span태그의 내용이 사라진다.
동작결과
age가 10일떄는 if와 unless의 조건 모두 통과하므로 "미성년자"라는 span태그의 값이 붙어있다.
Switch
<h1>switch</h1>
<table border="1">
<tr>
<th>count</th>
<th>username</th>
<th>age</th>
</tr>
<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>
</table>
th:case 를 이용해서 해당 값이 맞으면 해당 속성이 포함된 span을 출력하고 아니면 출력하지않는다.
th:case="*"은 기본값을 의미한다 (위에서 어떤 case도 맞지않았을때)
유저A의 age는 10이였으므로 th:case = "10"에 걸려서 10살이 출력
유저B의 age는 20이였으므로 th:case = "20"에 걸려서 20살이 출력
유저C의 age는 30이였으므로 둘다 걸리지않고 th:case="*" 으로 인해 기본값인 기타가 출력되었다.
주석
1. 표준 HTML 주석
뷰 템플릿
<h1>1. 표준 HTML 주석</h1>
<!--
<span th:text="${data}">html data</span>
-->
결과 페이지
h1태그로인해 제목만 나오고 아무것도 보이지않는다.
결과 페이지의 소스보기
소스에 주석이 그대로 보인다.!! 렌더링은 하지않지만 주석자체를 그대로 냅둔다.
2. 타임리프 파서 주석
뷰 템플릿
<h1>2. 타임리프 파서 주석</h1>
<!--/* [[${data}]] */-->
<!--/*-->
<span th:text="${data}">html data</span>
<!--*/-->
결과
제목빼고, 주석에 들어간것은 아무것도 렌더링 되지않음
결과 페이지의 소스보기
소스에서도 보이지않는다.
그렇다면 렌더링 하지않고 html파일을 웹브라우저에서 연다면?
타임리프 파서 주석이 동작하지않아. 내용이 보이게된다.
소스보기
이런식으로 되버리기 때문에 웹브라우저에서 열면 보인다.
주로 타임리프 파서 주석을 사용한다고 한다.
뷰 템플릿을 사용하면 주석이 동작하고, 웹브라우저에서 html파일을 실행하면 주석이 동작하지않아 실행되는.
3. 타임리프 프로토타입 주석
뷰 템플릿
<h1>3. 타임리프 프로토타입 주석</h1>
<!--/*/
<span th:text="${data}">html data</span>
/*/-->
결과 페이지
결과 페이지의 소스보기
만약 파일로 열어봤다면? (뷰 템플릿으로 렌더링 된게 아니라 웹 브라우저로 실행됬다면?)
보이지 않는다.
소스로 봐도 주석이 잘되어있는걸 확인할 수 있따.
'인프런 > 스프링 MVC 2편' 카테고리의 다른 글
6) 메시지 ,국제화 (0) | 2023.02.02 |
---|---|
5)타임리프 - 라디오버튼,셀렉트박스 (0) | 2023.02.02 |
4)타임리프 적용,체크박스,멀티체크박스 (0) | 2023.02.02 |
3) 타임리프 (블록 , 자바스크립트 인라인 , 템플릿 조각, 템플릿 레이아웃) (0) | 2023.02.01 |
1)타임리프 - 기본기능 (escape,unescape,스프링EL표현법,지역변수,기본객체,유틸리티객체,날짜객체,url링크) (0) | 2023.01.30 |
댓글