💡 데이터를 위한 데이터
엔티티 메타 데이터 ⇒ 엔티티 생성일자, 생성자, 수정일자, 수정자
Spring Data JPA에서 제공하는 엔티티 감시(Auditing) 기능을 활성화하기 위해 @EnableJpaAuditing
어노테이션을 포함한 설정 클래스를 작성한다.
이를 통해, Spring Data JPA는 엔티티의 생명 주기 이벤트를 리스닝하며, 이벤트가 발생할 때 적절한 동작을 수행할 수 있도록 설정할 수 있다.
본 포스팅에서는 엔티티가 생성 또는 수정 될 때 메타데이터가 자동으로 설정되도록 하기 위해 @EnableJpaAuditing
어노테이션을 사용한다.
package com.ourhours.server.global.config.jpa;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@Configuration
@EnableJpaAuditing
public class JpaAuditingConfiguration {
}
엔티티의 생명 주기 이벤트를 리스닝하며, 엔티티가 생성 또는 수정 될 때 메타데이터가 자동으로 설정되도록 하기 위한 클래스로, 다른 엔티티 클래스들이 상속 받아 사용할 수 있도록 한다.
package com.ourhours.server.global.model;
import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.ourhours.server.domain.member.domain.entity.Member;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
@CreatedDate
private LocalDateTime createAt;
@CreatedBy
@ManyToOne
private Member createdBy;
@LastModifiedDate
private LocalDateTime modifiedAt;
@LastModifiedBy
@ManyToOne
private Member modifiedBy;
}
@MappedSuperclass
: 해당 어노테이션이 포함된 클래스가 엔티티 클래스가 아니라, 매핑 정보를 포함한 부모 클래스임을 나타낸다.
이 클래스를 상속하는 엔티티 클래스에서는 부모 클래스의 필드와 매핑 정보를 공유할 수 있기 때문에 공통적으로 사용되는 필드와 매핑 정보를 재사용 할 수 있게 된다.
@EntityListeners(AuditingEntityListener.class)
: 해당 어노테이션이 포함된 클레스에 엔터티에서 발생하는 이벤트에 대한 리스너를 등록한다. 여기서는 AuditingEntityListener
를 사용하여 엔티티 생성일자, 생성자, 수정일자, 수정자와 같은 메타 데이터를 자동으로 관리할 수 있도록 한다.
@CreatedDate
/ @LastModifiedDate
각각 엔티티의 생성일자와 마지막 수정일자를 나타낸다.
@CreatedBy
/ @LastModifiedBy
각각 엔티티를 생성한 사용자와 마지막으로 수정한 사용자를 나타낸다.
* 해당 어노테이션을 사용하기 위해서는 별도의 구현체가 필요하다.
Spring Data JPA에서 제공하는 인터페이스 중 하나로, 엔터티의 생성자와 수정자를 자동으로 관리하기 위한 메서드 getCurrentAuditor
를 정의하는 데 사용된다.
getCurrentAuditor
메서드는 현재 Audit 이벤트를 실행하는 사용자를 결정하기 위해 호출되는 메소드로, 일반적으로, 시스템에서 정의한 기준에 따라 생성자 또는 수정자를 결정하는 데 사용된다.
따라서, AuditorAware
인터페이스를 구현하면, getCurrentAuditor
메서드 내에서 필요한 로직을 구현하여 어떻게 현재 사용자를 식별할 지를 정의할 수 있다.
package com.ourhours.server.global.util.jpa;
import java.util.Optional;
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import com.ourhours.server.domain.member.domain.entity.Member;
import com.ourhours.server.domain.member.repository.MemberRepository;
import com.ourhours.server.global.model.security.JwtAuthentication;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class CustomAuditorAware implements AuditorAware<Member> {
private final MemberRepository memberRepository;
@Override
public Optional<Member> getCurrentAuditor() {
return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
.filter(Authentication::isAuthenticated)
.map(authentication -> {
JwtAuthentication jwtAuthentication = (JwtAuthentication)authentication;
return memberRepository.findById(jwtAuthentication.getMemberId());
})
.orElse(Optional.empty());
}
}
SecurityContextHolder.getContext().getAuthentication()
이 null이 아니고
isAuthenticated
가 참인 경우에는, Authentication에 포함된 Member 식별자로 Member 객체를 찾아 반환하고,
그렇지 않은 경우에는, 빈 Optional 객체를 반환한다.