thymeleaf

ppp·2025년 7월 14일

타임리프는 템플릿 엔진이다. 템플릿 엔진은 서버에서 데이터를 받아 우리가 보는 웹 페이지, 즉 HTML 상에 데이터를 넣어 보여주는 도구이다.

의존성 추가

build.gradle 파일에 의존성을 추가해야 타임리프를 사용할 수 있다.

dependencies {
    ...
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}

표현식과 문법

■ 타임리프 표현식

표현식설명
${…}변수의 값 표현식
#{…}속성 파일 값 표현식
@{…}URL 표현식
*{…}선택한 변수의 표현식. th:object에서 선택한 객체에 접근

■ 타임리프 문법

표현식설명예제
th:text텍스트를 표현할 때 사용th:text=${person.name}
th:each컬렉션을 반복할 때 사용th:each=”person : ${persons}”
th:if조건이 true인 때만 표시th:if=”${person.age} ≥ 20”
th:unless조건이 false인 때만 표시th:unless=”${person.age} ≥ 20”
th:href이동 경로th:href=”@{/person/{id}(id=${person.id})}”
th:with변숫값으로 지정th:with=”name=${person.name}”
th:object선택한 객체로 지정th:object=”${person}”

뷰 컨트롤러

API 컨트롤러는 데이터를 직렬화한 JSON 문자열을 반환하며 @RestController 애너테이션을 사용한다. 뷰 컨트롤러는 모델 객체 값을 지정 및 뷰의 이름을 반환하며 @Controller 애너테이션을 사용한다.

@Controller
public class ExampleController {

  @GetMapping("/thymeleaf/example")
  public String thymeleafExample(Model model) {
    Person examplePerson = new Person();
    examplePerson.setId(1L);
    examplePerson.setName("홍길동");
    examplePerson.setAge(11);
    examplePerson.setHobbies(List.of("운동", "독서"));

    model.addAttribute("person", examplePerson);
    model.addAttribute("today", LocalDate.now());

    return "example";
  }

  @Setter
  @Getter
  class Person {
    private Long id;
    private String name;
    private int age;
    private List<String> hobbies;
  }
}
  • @Controller 이므로 뷰의 이름을 반환한다. 스프링은 반환하는 뷰의 이름을 보고 /resources/templates 디렉터리에서 파일을 찾아 웹 브라우저에 해당 파일을 보여준다.

  • Model 객체는 뷰인 HTML 쪽으로 값을 넘겨주는 객체이다. addAttribute() 메서드로 모델에 값을 저장한다. 모델을 컨트롤러와 뷰의 중간다리 역할이라고 생각하면 된다.

뷰 작성

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>타임리프 익히기</h1>
  <p th:text="${#temporals.format(today, 'yyyy-MM-dd')}"></p>
  <div th:object="${person}">
    <p th:text="|이름 : *{name}|"></p>
    <p th:text="|나이 : *{age}|"></p>
    <p>취미</p>
    <ul th:each="hobby : *{hobbies}">
      <li th:text="${hobby}"></li>
      <span th:if="${hobby == '운동'}">(대표 취미)</span>
    </ul>
  </div>
  <a th:href="@{/api/articles/{id}(id=${person.id})}">글 보기</a>
</body>
</html>
  • 타임리프의 문법과 표현식을 사용해서 HTML 파일을 작성한다.

  • #temporals.format() 함수로 LocalDate 타입인 오늘 날짜를 String 타입으로 포매팅한다.

엔티티에 생성, 수정 시간 추가

@EntityListeners(AuditingEntityListener.class)
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Article {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", updatable = false)
  private Long id;

  @Column(name = "title", nullable = false)
  private String title;

  @Column(name = "content", nullable = false)
  private String content;

  @CreatedDate
  @Column(name = "created_at")
  private LocalDateTime createdAt;

  @LastModifiedDate
  @Column(name = "updated_at")
  private LocalDateTime updatedAt;

  @Builder
  public Article(String title, String content) {
    this.title = title;
    this.content = content;
  }

  public void update(String title, String content) {
    this.title = title;
    this.content = content;
  }
}
  • @CreatedDate 애너테이션을 사용하면 엔티티의 생성 시간을 특정 컬럼에 저장할 수 있다.

  • @LastModifiedDate 애너테이션을 사용하면 엔티티가 수정될 때 마지막으로 수정된 시간을 특정 컬럼에 저장할 수 있다.

  • 엔티티의 생성 및 수정 시간을 자동으로 감시하고 기록하기 위해 @EntityListeners(AuditingEntityListener.class) 애너테이션을 추가한다.

@EnableJpaAuditing
@SpringBootApplication
public class SpringBootDeveloperApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootDeveloperApplication.class, args);
  }
}
  • @CreatedDate , @LastModifiedDate 애너테이션이 동작하려면 @EnableJpaAuditing 애너테이션을 추가해 JPA Auditing을 활성화해야 한다.

0개의 댓글