본문 바로가기
🖥Web/🔥SpringBoot

[SpringBoot] JPA Auditing이란? Auditing example

by 후누스 토르발즈 2022. 6. 6.
반응형

JPA Auditing이란? Auditing example

  1. JPA Auditing이란?
  2. 어노테이션 기반 감사 메타데이터
  3. 엔티티 클래스에 상속
  4. 활성화 어노테이션 추가

 

JPA Auditing이란?

보통 엔티티에는 해당 데이터의 생성시간과 수정시간을 포함합니다. 언제 만들어졌는지, 언제 수정되었는지 등은 차후 유지보수에 있어 굉장히 중요한 정보이기 때문입니다. 그렇다 보니 매번 DB에 삽입하기 전, 갱신하기 전에 날짜 데이터를 등록/수정하는 코드가 여기저기 들어가게 되는데, 이러한 반복적인 코드가 모든 테이블과 서비스 메소드에 포함되는것은 굉장히 불편한 일입니다.

 

Spring Data는 엔티티를 생성하거나 변경한 사람과 발생한 시점을 투명하게 추적하기 위한 정교한 지원을 제공합니다.

해당 기능의 이점을 얻으려면 어노테이션을 이용하거나 인터페이스를 구현하여 정의할 수 있는 감사 메타데이터를 엔티티 클래스에 제공해야 합니다.

 

  • Spring Data
    • 기본 데이터 저장소의 특수 특성을 유지하면서 데이터 액세스를 위한 친숙하고 일관된 Spring 기반 프로그래밍 모델을 제공하는것
  • Spring Data JPA
    • JPA에 대한 Spring Data 저장소 지원

 

 

어노테이션 기반 감사 메타데이터

package com.example.springboot;

import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {

    @CreatedDate
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime modifiedDate;

}

BaseTimeEntity클래스는 모든 Entity의 상위 클래스가 되어 Entity들의 createDate, modifiedDate를 자동으로 관리하는 역할을 하게됩니다.

 

  • @MappedSuperclass
    • JPA Entity 클래스들이 BaseTimeEntity을 상속할 경우 필드들(createdDate, modifiedDate)도 칼럼으로 인식합니다.
  • @EntityListeners(AuditingEntityListener.class)
    • Entity 또는 매핑된 수퍼클래스에 사용할 콜백 리스너 클래스를 지정합니다.
    • 이 어노테이션은 엔티티 클래스 또는 매핑된 수퍼클래스에 적용될 수 있습니다.
    • BaseTimeEntity 클래스에 Auditing 기능을 포함시킵니다.
  • @CreateDate
    • Entity가 생성되어 저장될 때 시간이 자동 저장됩니다.
  • @LastModifiedDate
    • 조회한 Entity의 값을 변경할 때 시간이 자동 저장됩니다.

 

엔티티 클래스에 상속

package com.example.springboot.domain.posts;

import com.example.springboot.BaseTimeEntity;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Id;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Column;

@Getter
@NoArgsConstructor
@Entity
public class Posts extends BaseTimeEntity {	// 상속
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 500, nullable = false)
    private String title;

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

    private String author;

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

    public void update(String title, String content){
        this.title = title;
        this.content = content;
    }
}

 

 

활성화 어노테이션 추가

package com.example.springboot;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing // 추가
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Application클래스에 활성화 어노테이션 추가합니다.

  • @EnableJpaAuditing
    • JPA Auditing 활성화

 

테스트

package com.example.springboot.web.domain.posts;

import com.example.springboot.domain.posts.PostsRepository;
import com.example.springboot.domain.posts.Posts;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.time.LocalDateTime;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest
public class PostsRepositoryTest {

    @Autowired
    PostsRepository postsRepository;

    @After
    public void cleanup() {
        postsRepository.deleteAll();
    }

    @Test
    public void BaseTimeEntity_등록() {
        // given
        LocalDateTime now = LocalDateTime.of(2022,6,6,0,0,0);
        postsRepository.save(Posts.builder()
                .title("title")
                .content("content")
                .author("author")
                .build());

        // when
        List<Posts> postsList = postsRepository.findAll();

        // then
        Posts posts = postsList.get(0);

        System.out.println(">>>>>>>>> createDate="+posts.getCreatedDate()+", modifiedDate="+posts.getModifiedDate());

        assertThat(posts.getCreatedDate()).isAfter(now);
        assertThat(posts.getModifiedDate()).isAfter(now);
    }
}

 

JPA Auditing 테스트 결과

 

 

반응형