Thymeleaf 기본(SpringBoot)
Thymeleaf
타임리프도 JSP처럼 서버에서 결과를 만들어 브라우저로 전송
사용하기 위해 application.properties에서 spring.thymeleaf.cache=false로 설정
타임리프에서 에러가 나면 스크롤을 내려 중앙부분을 보면 확인할 수 있음
특징
타임리프는 속성으로 되어있기 때문에 그냥 html로 열면 퍼블리셔가 화면에 코딩한 그대로 화면에서 볼 수 있음 (서버에서 받아와야하는 값들 알 수 없음)
JSP는 확장자가 JSP라서 이런거 못함
기본 설정(DTO, Controller)
// SampleDTO
@Data // JPA할 때 무한 참조가 일어날 수 있으므로 사용에 유의
@Builder(toBuilder = true)
public class SampleDTO {
private Long sno;
private String first;
private String last;
private LocalDateTime regTime;
}
// SampleController
@GetMapping("/ex2")
public void exModel(Model model){
List<SampleDTO> list = IntStream.rangeClosed(1,20).asLongStream().mapToObj(i -> {
SampleDTO dto = SampleDTO.builder()
.sno(i)
.first("First.."+i)
.last("Last.."+i)
.regTime(LocalDateTime.now())
.build();
return dto;
}).collect(Collectors.toList());
model.addAttribute("list", list);
}
* 참고: 자바에서 중괄호 나오면 배열 ((@Getmapping("/ex2", "/ex3") 하면 두 url모두 접근 가능함)
반복문
state를 통해 인덱스 번호를 부여하는 것도 가능함
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 반복문 -->
<ul>
<li th:each="dto: ${list}">
[[${dto}]] <!-- 대괄호 2겹: 그대로 인라인으로 출력, 객체 하나씩 출력 -->
<a th:text="${dto}"></a> <!-- 태그 포함하여 출력 -->
</li>
</ul>
</body>
</html>
제어문
if를 통한 조건문이 사용이 가능하며, 이외에 unless를 통한 else처리, 삼항연산자 등을 이용할 수 있음
- 예시: 5의 배수에만 빨간 배경
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.target{
background-color: red;
}
</style>
</head>
<body>
<ul>
<li th:each="dto, state: ${list}" th:class="${dto.sno % 5 == 0} ? 'target'" th:text="${dto}" > <!-- state를 통해서 인덱스 번호 붙여주기, 조건문 부여 -->
[[${state.index}]] [[${dto}]]
</li>
</ul>
</body>
</html>
inline 속성
- SampleController 中
@GetMapping("/exInline")
public String exInline(RedirectAttributes redirectAttributes) {
SampleDTO dto = SampleDTO.builder()
.sno(100L)
.first("First.."+100)
.last("Last.."+100)
.regTime(LocalDateTime.now())
.build();
redirectAttributes.addFlashAttribute("result", "success");
redirectAttributes.addFlashAttribute("dto", dto);
return "redirect:/sample/ex3";
}
@GetMapping("/ex3")
public void ex3() {
log.info("ex3");
}
- ex3.html
<body>
<!--1-->
<h1 th:text="${result}"></h1>
<h1 th:text="${dto}"></h1>
<!--2-->
<script th:inline="javascript">
var msg = [[${result}]];
var dto = [[${dto}]];
</script>
<!--3-->
<script>
var msg = '[[${result}]]';
var dto = '[[${dto}]]';
</script>
</body>
- 출력
- 타임리프를 활용할 경우 javascript 코드에 model처럼 속성을 넣을 수 있음
- 자바 스크립트와 서버에서 변수는 완전히 별개임. 서버 입장에서는 result라는 값을 그저 타임리프를 통해 출력하는 것.
- 따라서 원래대로라면 2번에서 따옴표 없이 사용할 경우 에러가 나야함
- 그러나 'th:inline="${result}"'를 통해 inline javascript 속성을 주었기 때문에 웹의 개발자 도구에서 보면 자동으로 따옴표가 생겨있음을 볼 수 있음
- 2번에서 객체는 원래 DTO 객체 형태 그대로 출력이 되어야하나, inline을 부여했기 때문에 js 객체 형태로 출력이 됨
링크 처리
@{}
를 통해서 링크를 부여할 수 있음.
- SampleController
@GetMapping({"/ex2", "/exLink"}) // 배열을 통해 여러개 mapping이 가능함
public void exModel(Model model){
List<SampleDTO> list = IntStream.rangeClosed(1,20).asLongStream().mapToObj(i -> {
SampleDTO dto = SampleDTO.builder()
.sno(i)
.first("First.."+i)
.last("Last.."+i)
.regTime(LocalDateTime.now())
.price(12345)
.build();
return dto;
}).collect(Collectors.toList());
model.addAttribute("list", list);
}
- exLink.html
<li th:each="dto:${list}">
<!-- 파라미터 여러개면 콤마를 통해 여러개 활용 가능-->
<a th:href="@{/sample/exView(sno=${dto.sno}, first=${dto.first})}">
[[${dto}]]
</a>
</li>
포맷팅
<!-- 화면에 나타나는 글자를 모두 5자리로 만들어야할 때 다음과 같이 작성 -->
[[${#numbers.formatInteger(dto.sno, 5)}]]
<!-- 가격 세자리마다 콤마 직어주기 -->
[[${#numbers.formatInteger(dto.price,3,'COMMA')}]]
<!-- 날짜 포맷팅 해주기, 옛날에는 dependency 추가했어야했는데 이제는 추가 없이 활용 가능함 -->
[[${#temporals.format(dto.regTime, 'yyyy/MM/dd')}]]
html 태그가 서버에서 넘어오는 내용에 담겼을 경우
- 타임리프는 별도의 확장자가 없으며 속성으로 구성되어 있기 때문에 그냥 html로 열면 퍼블리셔가 화면에 코딩한 내용을 그대로 볼 수 있음
- JSP는 확장자가 JSP이므로 html자체로 열 수 없음
- 타임리프를 활용하면 서버에서 받아와야하는 값을 알 수 없음
<h1 th:text="${'Hello World'}"></h1>
<h2 th:text="${name}">이순신</h2> <!--name값이 홍길동이므로 화면에 홍길동이라 나옴 -->
<th:block th:text="${content}"></th:block> <!--html 글자 그대로 찍힘-->
[[${content}]]
<th:block th:utext="${content}"></th:block> <!--html 형식이 적용되어 출력됨 -->
[(${content})]
주석
<!--html 주석은 개발자 도구에서 볼 수 있음 -->
<!--/* 타임리프 주석은 개발자 도구에서 안보임 */-->