우와한 개발자

[ Thymeleaf ] 기본 문법(2) - 폼 바인딩, 프래그먼트, 유틸리티 객체, 연산자, 에러 처리

by 우와한개발자

1. 폼 바인딩

1) th:object

  • <form> 태그에 객체를 지정해서 하위 필드에서 객체명 없이 필드에 바로 접근
  • ${user.name} 대신 {name}으로 줄여 쓸 수 있음
<form th:action="@{/user/save}" method="post" th:object="${user}">
    <input type="text" th:field="*{name}" />
    <input type="email" th:field="*{email}" />
    <input type="text" th:field="*{phone}" />
    <button type="submit">저장</button>
</form>

 

2) th:field

  • id, name, value 속성을 한 번에 자동으로 설정해줌
  • th:object와 함께 사용
<input type="text" th:field="*{name}" />
<!-- 결과: <input type="text" id="name" name="name" value="홍길동" /> -->

 

2. fragment 프레그먼트 (재사용 레이아웃)

  • 공통 HTML 조각(header, footer, nav 등)을 별도 파일로 분리하고 재사용

1) fragment 정의 (th:fragment)

<!-- fragments/layout.html -->
<header th:fragment="header">
    <nav>공통 네비게이션</nav>
</header>

<footer th:fragment="footer">
    <p>공통 푸터</p>
</footer>

 

2) fragment 삽입

속성 의미
th:insert 현재 태그 내부에 프래그먼트를 삽입 (태그 유지)
th:replace 현재 태그 자체를 프래그먼트로 교체
<!-- th:insert: <div> 태그 안에 header가 들어옴 -->
<div th:insert="~{fragments/layout :: header}"></div>

<!-- th:replace: <div> 태그가 header로 완전히 교체됨 -->
<div th:replace="~{fragments/layout :: footer}"></div>

 

3. 유틸리티 객체

  • Thymeleaf에서 기본으로 제공하는 유틸리티 객체
  • 뷰에서 간단한 포맷팅이나 변환을 처리할 때 사용.
객체 용도
#strings 문자열 처리
#numbers 숫자 포맷
#dates java.util.Date 포맷
#temporals java.time (LocalDate 등) 포맷
#lists 리스트 관련
#maps 맵 관련
#nulls null 처리
<!-- 문자열 -->
<p th:text="${#strings.toUpperCase(user.name)}"></p>
<p th:text="${#strings.isEmpty(user.name)} ? '이름 없음' : ${user.name}"></p>

<!-- 숫자 (세 자리마다 콤마) -->
<p th:text="${#numbers.formatInteger(product.price, 3, 'COMMA')}"></p>
<!-- 결과: 1,000,000 -->

<!-- 날짜 포맷 -->
<p th:text="${#dates.format(user.joinDate, 'yyyy-MM-dd')}"></p>

<!-- LocalDate 포맷 (java.time) -->
<p th:text="${#temporals.format(user.joinDate, 'yyyy-MM-dd')}"></p>

 

4. 비교 연산자

  • HTML에서 <, > 는 태그로 인식되기 때문에 Thymeleaf에서는 텍스트 별칭을 사용하는 것을 권장
기호 텍스트 별칭 의미
> gt 크다
< lt 작다
>= ge 크거나 같다
<= le 작거나 같다
== eq 같다
!= ne 같지 않다
<!-- 기호 사용 (HTML에서 < > 가 태그로 해석될 수 있어 주의) -->
<p th:if="${user.age >= 20}">성인입니다.</p>

<!-- 텍스트 별칭 사용 (권장) -->
<p th:if="${user.age ge 20}">성인입니다.</p>
<p th:if="${user.age lt 20}">미성년자입니다.</p>
<p th:if="${user.role eq 'ADMIN'}">관리자입니다.</p>

 

5. 에러 처리

1) th:errors

  • Spring Validation과 연동해서 폼 유효성 검사 실패 시 필드별 에러 메시지를 출력하는 속성
  • BindingResult에 담긴 에러를 뷰에서 출력할 때 사용
  • 해당 필드에 에러가 없으면 태그 자체가 렌더링되지 않음
<form th:action="@{/user/save}" method="post" th:object="${user}">

    <input type="text" th:field="*{name}" />
    <!-- name 필드에 에러가 있을 때만 출력 -->
    <span th:errors="*{name}"></span>

    <input type="email" th:field="*{email}" />
    <span th:errors="*{email}"></span>

    <button type="submit">저장</button>
</form>
// Controller
@PostMapping("/user/save")
public String save(@Valid UserDto user, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "user/form"; // 에러가 있으면 폼으로 다시 이동
    }
    userService.save(user);
    return "redirect:/user/list";
}
// DTO - Bean Validation 어노테이션
@Getter
@Setter
public class UserDto {

    @NotBlank(message = "이름은 필수입니다.")
    private String name;

    @Email(message = "이메일 형식이 올바르지 않습니다.")
    @NotBlank(message = "이메일은 필수입니다.")
    private String email;

    @Min(value = 1, message = "나이는 1 이상이어야 합니다.")
    private int age;
}

 

2) th:errorclass

  • 해당 필드에 에러가 있을 때 자동으로 CSS 클래스를 추가하는 속성
  • th:field와 함께 사용하며, 에러가 있는 입력 필드를 빨간 테두리 등으로 강조할 때 활용
<form th:object="${user}">
    <!-- name 필드에 에러가 있으면 'error-input' 클래스가 자동으로 추가됨 -->
    <input type="text" th:field="*{name}" th:errorclass="error-input" />
    <span th:errors="*{name}"></span>

    <input type="email" th:field="*{email}" th:errorclass="error-input" />
    <span th:errors="*{email}"></span>
</form>

블로그의 정보

우와한개발자 님의 블로그

우와한개발자

활동하기