타임리프 기본 사용법

텍스트 출력

  1. html 콘텐츠에 내용 출력 → th:text=”${data}”
  2. 컨텐츠 안에서 직접 출력 = [[${data}]]

Espace 기본 제공

  1. html은 <, > 등등의 특수문자 기반으로 화면 생성
  2. html 엔티티 : <, >를 문자로 표현하는 방법 = &lt, &gt
  3. th:text, [[${data}]] 는 기본적으로 이스케이프 제공
  4. th:utext, [(${data})] → 이스케이프 제공 x

기본 객체 제공

  1. ${#request}
  2. ${#response}
  3. ${#session}
  4. ${#servletContext}
  5. ${#locale}

연산 기능 제공

  1. html 안에서 연산을 사용할 수 있다.
  2. th:text=”1+3” → 4가 화면에 나옴
    1. &gt, gt,, ge, ≥, ==, +, -, %, *, ≠ 다 사용 가능
    2. th:text=”(10 % 2 == 0)? ‘짝수’ : ‘홀수’ “ (조건식 사용 가능)
  3. Elvis 연산자
    1. 데이터 있는지 없는지에 따라 다른 값이 나오도록 할 수 있다.
    2. th:text=”${data}? ‘데이터가 없습니다’ ”
    3. 조건식의 축약 버전
  4. No- Operation
    1. th:text=”${data}? _ ”
    2. 데이터 없으면 타임리프가 렌더링을 안한다.

속성 값 설정

  1. th:* 사용해서 html 태그 내의 속성 값 설정
  2. 기존 속성 있으면 대체, 없으면 새로 만듦 - 기본 값 만들어놓고 디버깅 가능
    1. th:attrappend : 속성 뒤에 값 추가
    2. th:attrperpend: 속성 앞에 값 추가
    3. th:classappend: 클래스 뒤에 값 추가
  3. checked 처리
    1. html checked → true,false 상관없이 그냥 체크 표시 나옴
    2. th:checked=”false”면 checked 지워버림

반복

  1. 반복 상태 유지
    1. th:each 사용하면 됨
    2. List, Map, 배열, Iterable 등등 다 가능
    3. “user, userStat : ${userList}”
    4. userStat에 현재 반복 상태 알려줌, 생략 가능 → +Stat으로 들어감
      1. userStat.index : 0 부터 시작하는 인덱스
      2. count: 1 부터 시작함
      3. size: 전체 사이즈
      4. event, odd : 홀수, 짝수 여부
      5. first, last: 처음, 마지막 여부
      6. current 현재 객체

템플릿 조각과 레이아웃

<div th:fragment="users_header (title)" class="title">
    <div class="header">
        <h1><a href="/">Admin</a></h1>
        <p><a href="/admin/users">[유저 서비스]</a></p>
    </div>
    <p th:text="${title}"></p>
</div>
<!DOCTYPE HTML>
<html xmlns: th=”http://www.thymeleaf.org”>
<head>
    <meta charset="utf-8">
    <title>BlazingDevs Calender!</title>
    <link th:href="@{/css/menu.css}" rel="stylesheet" />
</head>
<body>
    <div th:replace="~{template/fragment/header :: users_header ('유저관리')}" class="title">
        <h1>유저 관리</h1>
    </div>
    ...
</body>
</html>

th:fragment를 사용하면 템플릿을 조각처럼 만들어놓고 사용할 수 있다.

네비게이션 바와 같은 여러 템플릿에서 공유하는 부분을 만들어 놓고 사용하면 편할 것 같다.

 

html 태그에 fragment를 사용하여 기본 레이아웃을 만들어 놓고 사용할 수도 있다.

 

스프링 통합 기능

th:object, th:field를 사용하면 템플릿에 객체를 넘겨주고 form 태그를 편리하게 사용할 수 있다.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CreateScheduleRequest{
    private String workspace;
    private String name;
    private List<String> users;
}
    @GetMapping("/admin/schedules/create-schedules")
    public String createScheduleForm(Model model){
        
        List<Workspace> workspaces = workspaceService.findAll()
        List<User> users = userService.findAll();
        
        List<String> workspaceList = workspaces.stream()
            .map(w -> w.getName())
            .collect(toList());
        
        List<String> userList = users.stream()
            .map(u -> u.getAccountId())
            .collect(toList());
        
        model.addAttribute("workspaceList", workspaceList);
        model.addAttribute("userList", userList);
        model.addAttribute("schedule", new CreateScheduleRequest());
        
        return "admin/schedules/schedules-create-form";
    }

스케줄 생성 폼에 생성에 필요한 내용을 담고 있는 CreateScheduleRequest 객체를 넘겨줬다.

<body>
    <div th:replace="~{template/fragment/header :: schedules_header ('스케줄생성')}" class="title">
        <h1>스케줄 생성</h1>
    </div>

    <div class="container">
        <form role="form" action="/admin/schedules/create-schedules" method="post" th:object="${schedule}">
            <div class="form-group">
                <label>이름</label>
                <input type="text" th:field="*{name}" class="form-control" placeholder="이름을 입력하세요"/>
            </div>
            <div class="form-group">
                <label>워크스페이스</label>
                <select th:field="*{workspace}">
                    <option th:each="workspace: ${workspaceList}" th:value="${workspace}"
                            th:text="${workspace}"></option>
                </select>
            </div>
            <div class="form-group">
                <label>유저</label>
                <details>
                    <summary> 유저 보기 </summary>
                    <ul>
                        <li th:each="user : ${userList}">
                            <input th:field="*{users}" type="checkbox" th:text="${user}" th:value="${user}" />
                        </li>
                    </ul>
                </details>
            </div>
            <button type="submit" class="btn">생성</button>
        </form>
    </div>
</body>

th:object="${schedule}" 를 사용하면 form에서 model로 받아온 객체를 사용할 수 있다.

th:field="*{name}"를 사용하면 가져온 객체(schedule)의 name 필드를 사용할 수 있다.

th:field를 사용하면

  1. 태그에 name, id 를 자동으로 만들어준다.
  2. field 안에 값이 있을 경우 value도 만들어준다.
  3. checkbox 타입에선 value와 field의 값을 비교하여 checked 속성과 히든 태그를 만들어준다.

validation에서도 사용할 수 있다. 고 하는데 강의를 더 들어봐야 할 것 같다

 

@ModelAttribute NoArgs Setter 이슈

어드민 페이지를 만들면서 파라미터로는 값을 잘 전달하는데

ModelAttribute에서 변환하는 과정에서 객체 프로퍼티에 null값이 전달되는 일이 있었다.

 

ModelAttribute에서 파라미터로 넘어온 값을 이용해서 객체를 생성할때

  1. 파라미터 없는 기본 생성자(NoArgsConstructer 등)로 객체 생성 후 Setter로 초기화
  2. 파라미터 존재하는 생성자로 생성하면서 초기화

순으로 진행하기 때문에

 

파라미터 없는 생성자가 있을 경우 Setter를 달아줘야한다.

 

 

 

 

+ Recent posts