본문 바로가기
개발관련

JPA) JPA Auditing 사용하기

by 수바니 2024. 9. 5.

JPA Auditing이란?

JPA Auditing은 Spring Data JPA에서 제공하는 기능 중 하나로, 엔티티가 생성되거나 수정될 때 자동으로 생성일, 수정일, 생성자, 수정자를 기록하는 기능입니다. 이 기능을 사용하면 데이터베이스 테이블에 발생하는 변화 내역을 쉽게 추적할 수 있습니다.

 

1. 의존성추가

Spring Data JPA 의존성을 추가합니다.

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

 

 

2. 엔티티 클래스에 Auditing 필드 추가

엔티티 클래스에

@CreatedDate, @LastModifiedDate, @CreatedBy, @LastModifiedBy

어노테이션을 추가하여 자동으로 값을 기록합니다.

@Entity
@EntityListeners(AuditingEntityListener.class)
public class YourEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime modifiedDate;

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String modifiedBy;
}

 

 

3. Auditing 활성화

@EnableJpaAuditing 어노테이션을 사용하여 Auditing 기능을 활성화합니다.

@SpringBootApplication
@EnableJpaAuditing
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}

 

 

주요 어노테이션

@CreatedDate 엔티티가 생성된 시각을 기록
@LastModifiedDate 엔티티가 마지막으로 수정된 시각을 기록
@CreatedBy 엔티티가 생성된 사용자를 기록
@LastModifiedBy 엔티티가 마지막으로 수정된 사용자를 기록

 

 

4. AuditorAware 구현

@CreatedBy와 @LastModifiedBy와 같은 필드를 채우려면 AuditorAware 인터페이스를 구현해야 합니다.

JPA Auditing을 통해 엔티티가 생성되거나 수정될 때 자동으로 날짜, 시간, 그리고 현재 작업 중인 사용자 정보를 기록할 수 있습니다. 이때, AuditorAware 인터페이스는 현재 사용자의 정보를 제공하는 역할

 

1) 고정된 사용자 반환

기본적으로, 특정 사용자 정보를 반환하도록 설정할 수 있습니다. 이는 주로 테스트 환경에서 사용

@Component
public class AuditorAwareImpl implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("Admin"); // 항상 "Admin"이라는 고정된 사용자 반환
    }
}

 

위 코드에서는 고정된 "Admin" 값을 반환하며, 이는 엔티티가 생성되거나 수정될 때 "Admin"이 작업한 것으로 기록됩니다. 하지만, 실제 애플리케이션에서는 현재 로그인한 사용자 정보를 반환

 

 

2) Spring Security와 연동하여 현재 사용자 반환

실제 애플리케이션에서는 보통 Spring Security와 연동하여 현재 로그인한 사용자를 getCurrentAuditor()에서 반환하도록 설정

@Component
public class AuditorAwareImpl implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        // Spring Security의 인증 정보를 가져옴
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        // 인증된 사용자가 없거나 익명 사용자일 경우
        if (authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal().equals("anonymousUser")) {
            return Optional.empty(); // 인증되지 않은 경우, 아무 것도 반환하지 않음
        }

        // 인증된 사용자의 이름을 반환
        return Optional.of(authentication.getName());
    }
}

 

 

SecurityContextHolder.getContext().getAuthentication(): Spring Security에서 현재 인증된 사용자의 정보를 가져옵니다.

authentication.getName(): 현재 로그인한 사용자의 이름을 반환합니다.

이 값이 @CreatedBy 또는 @LastModifiedBy에 자동으로 저장됩니다.

 

 

구현된 AuditorAware 클래스가 사용되는 방식

 

1. 엔티티 클래스에 Auditing 설정

엔티티 클래스에 @CreatedBy, @LastModifiedBy 필드를 추가하고

@EntityListeners(AuditingEntityListener.class)를 통해 JPA Auditing 기능을 활성화

 

@Entity
@EntityListeners(AuditingEntityListener.class)
public class MyEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String modifiedBy;

    // 기타 필드들
}

 

 

2. Auditing 활성화

Spring Boot 설정 클래스에서 @EnableJpaAuditing을 추가하여 JPA Auditing 기능을 전역적으로 활성화합니다.

아까 위의 코드와 동일합니다.

@SpringBootApplication
@EnableJpaAuditing
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}

auditorAwareRef는 AuditorAware 구현체의 빈 이름을 지정합니다.

이 설정을 통해 Spring Boot는 getCurrentAuditor() 메서드를 호출하여 자동으로 현재 사용자를 추적하고,

엔티티의 createdBy와 modifiedBy 필드를 업데이트합니다.

 

전체 흐름 요약

  1. AuditorAware 인터페이스 구현: 현재 사용자 정보를 반환하는 getCurrentAuditor() 메서드를 구현합니다.
  2. Auditing 활성화: Spring Boot 설정 클래스에서 @EnableJpaAuditing으로 Auditing을 활성화합니다.
  3. 엔티티에서 사용자 정보 기록: 엔티티에서 @CreatedBy와 @LastModifiedBy를 설정하고, 이 필드에 자동으로 현재 사용자 정보를 기록합니다.

이를 통해 데이터베이스에 기록되는 데이터를 누가 생성하고 수정했는지 쉽게 추적할 수 있으며, 주로 로그인 시스템과 연동하여 사용됩니다.

 

 

 

@MappedSuperClass

JPA에서 공통 엔티티 속성을 상속하기 위해 사용되는 어노테이션

@MappedSuperclass를 @EntityListeners와 함께 사용하면,

여러 엔티티에서 공통적으로 사용하는 필드를 한 번에 정의하고 해당 필드에 대한 감사(auditing) 기능을 손쉽게 적용할 수 있습니다.

즉, 공통된 속성(예: createdDate, createdBy, modifiedDate, modifiedBy)을 여러 엔티티에 반복하지 않고, 공통 상위 클래스에 정의한 후 상속받아 사용할 수 있습니다.

 

 

@MappedSuperclass의 역할

@MappedSuperclass는 다른 엔티티 클래스들이 상속받아 사용할 공통 속성을 정의할 때 사용됩니다.

직접 데이터베이스 테이블로 매핑되지 않고, 상속받는 엔티티 클래스에 매핑됩니다.

예를 들어, 여러 엔티티에 동일한 createdDate, modifiedDate, createdBy, modifiedBy 같은 필드가 있다면, 이를 각 엔티티에 개별적으로 정의하는 대신, @MappedSuperclass로 상위 클래스에 정의하고 상속하여 사용하면 코드가 간결해집니다.

 

@EntityListeners의 역할

@EntityListeners는 엔티티의 생명 주기(생성, 수정 등) 이벤트를 감지하여 특정 동작을 실행할 수 있게 합니다. 이를 통해 JPA Auditing 기능을 적용할 수 있습니다. @CreatedDate, @LastModifiedDate, @CreatedBy, @LastModifiedBy 필드에 값을 자동으로 넣는 것이 대표적인 사용 사례입니다.

@PrePersist Persist(Insert) 메서드가 호출되기 전에 실행되는 메서드
@PreUpdate Merge(Update) 메서드가 호출되기 전에 실행되는 메서드
@PreRemove Remove(Delete) 메서드가 호출되기 전에 실행되는 메서드
@PostPersist Persist(Insert) 메서드가 호출된 후에 실행되는 메서드
@PostUpdate Merge(Update) 메서드가 호출된 후에 실행되는 메서드
@PostRemove Remove(Delete) 메서드가 호출된 후에 실행되는 메서드
@PostLoad Select 조회가 실행된 직후에 실행되는 메서드

 

 

@MappedSuperclass + @EntityListeners 함께사용하는 경우

1.  공통 상위 클래스 정의 (@MappedSuperclass + @EntityListeners)

먼저, 여러 엔티티에 공통으로 적용할 필드와 Auditing 기능을 가진 상위 클래스를 정의합니다.

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

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

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)  // Auditing 기능 활성화
public abstract class BaseEntity {

    @CreatedDate
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime modifiedDate;

    @CreatedBy
    private String createdBy;

    @LastModifiedBy
    private String modifiedBy;

    // Getters and Setters
    public LocalDateTime getCreatedDate() {
        return createdDate;
    }

 ... 생략

}

 

 

 

@MappedSuperclass: 이 클래스는 데이터베이스에 직접 매핑되지 않고, 이를 상속하는 엔티티들이 상속받은 필드만 매핑됩니다.

@EntityListeners(AuditingEntityListener.class): AuditingEntityListener를 사용하여 Auditing 기능을 활성화합니다.

이를 통해 createdDate, modifiedDate, createdBy, modifiedBy 필드가 자동으로 채워집니다.

 

 

 

 2. 엔티티 클래스에서 상속 사용

이제 각 엔티티 클래스는 BaseEntity 를 상속받아 공통 필드를 재사용 할 수 있습니다.

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class User extends BaseEntity {

    @Id
    private Long id;
    private String name;
    
    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

생략...
}

 

User 엔티티는 BaseEntity를 상속받음으로써 createdDate, modifiedDate, createdBy, modifiedBy 같은 공통 필드를 자동으로 포함하게 됩니다.

이때, @CreatedBy, @LastModifiedBy 등의 필드는 AuditorAware 인터페이스 구현체에 의해 값이 채워집니다.