본문 바로가기

jpa

Auditing 사용해서 데이터 관리하기

JPA의 Auditing 기능을 사용하면 DB에 데이터 입력, 수정 시의 시간, 입력자 정보를 자동으로 관리할 수 있다.

보통 테이블을 생성하면 데이터 입력일자, 수정일자는 기본으로 넣게되는데 jpa에서 이를 자동으로 관리해준다.

 

@EnableJpaAuditing

먼저 jpa의 auditing 기능을 사용하려면 @EnableJpaAuditing 어노테이션을 사용해야한다. Application.java에 클래스 범위의 어노테이션으로 사용하면 인식 가능하지만, junit 테스트 시 @WebMvcTest와 충돌되는 문제가 있기 때문에 따로 JpaConfig라는 클래스를 생성해서 인식되도록 한다. 

 

JpaConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing //테스트 진행 시@WebMvcTest와 충돌을 막기위해 JpaConfig 별도 생성
public class JpaConfig {

}

 

@CreatedDate, @LastModifiedDate

@CreatedDate는 데이터의 최초 입력 시간, @LastModifiedDate는 데이터의 가장 마지막 입력 시간을 관리해준다.

데이터 입력 시간 관리는 여러 테이블에 공통적으로 사용되기 때문에 별도의 클래스로 생성한 뒤 다른 엔티티 클래스에서 상속받을 수 있도록 한다. 

@MappedSuperclass 어노테이션을 통해 다른 엔티티 클래스들이 해당 클래스를 상속받았을 때 createdDate, lastModifiedDate 필드들을 컬럼으로 인식하도록 한다.

@EntityListeners 어노테이션을 이용해 클래스에 Auditing 기능을 포함시킨다.

 Audit는 감독하고 검사하다는 뜻으로, 해당 데이터를 보고 있다가 생성 또는 수정이 발생하면 자동으로 값을 넣어준다.

 

BaseTimeEntity.java

import java.time.LocalDateTime;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;

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

import lombok.Getter;

@Getter
@MappedSuperclass //JPA Enitiy 클래스들이 BaseTimeEntity을 상속할 경우 필드들도 칼럼으로 인식하도록 함.
@EntityListeners(AuditingEntityListener.class) //클래스에 Auditing 기능을 포함시킴
public class BaseTimeEntity {
	
	@CreatedDate
	@Column(updatable = false)
	private LocalDateTime createdDate;
	
	@LastModifiedDate
	private LocalDateTime lastModifiedDate;

}

 

이후 원하는 엔티티 클래스에서 BaseTimeEntity 클래스를 상속한다.

 

Member.java

@Getter
@NoArgsConstructor
@Entity
public class Member extends BaseTimeEntity{
	
	...
	 
}

 

createdDate와 lastModifiedDate는 위의 설정으로 사용 가능하다.

데이터의 생성자, 수정자를 관리하는 @CreatedBy와 @LastModifiedBy는 한단계 더 필요로 하는데, JPA가 생성자, 수정자는 인식할 수 없기 때문에 AuditorAware를 구현해 Bean으로 등록해줘야 한다.

AuditorAware를 implements로 상속한 클래스로 구현해도 되지만 JpaConfig에서 빈으로 등록했다.

우선 테스트를 위해 Long 타입의 랜덤 숫자를 생성하고 테스트를 진행하였다.

 

JpaConfig.java

import java.util.Optional;
import java.util.Random;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import lombok.RequiredArgsConstructor;

@Configuration
@EnableJpaAuditing //테스트 진행 시@WebMvcTest와 충돌을 막기위해 JpaConfig 별도 생성
public class JpaConfig {


	@Bean
	public AuditorAware<Long> auditorAware() {
		return () -> {
			return Optional.of(new Random().nextLong());
		};
	}
}

 

 

테스트 코드

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

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

import com.tlog.backend.global.config.JpaConfig;
import com.tlog.backend.post.domain.Post;
import com.tlog.backend.post.domain.repository.PostRepository;
import com.tlog.backend.post.web.dto.PostRequest;

@ActiveProfiles("test")
@Import(JpaConfig.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class PostRepositoryTest {
	
	@Autowired
	PostRepository postRepository;
	
	@Test
	@DisplayName("게시물이 저장된다.")
	public void save_post_test() {
		//given
		String title = "post title";
		String content = "post content";
		
		Post entity = Post.builder()
				.title(title)
				.content(content)
				.build();
		//when
		Post savedPost = postRepository.save(entity);
		
		//then
		assertThat(savedPost.getTitle()).isEqualTo(title);
		assertThat(savedPost.getContent()).isEqualTo(content);
		
		assertThat(savedPost.getCreatedDate()).isNotNull();
		assertThat(savedPost.getCreatedBy()).isNotNull();
	}

}

 

이후 헤더로 전달되는 accessToken에서 사용자 id를 추출하는 방식으로 수정.

import java.util.Optional;
import javax.servlet.http.HttpServletRequest;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import com.tlog.backend.login.JwtProvider;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Configuration
@EnableJpaAuditing //테스트 진행 시@WebMvcTest와 충돌을 막기위해 JpaConfig 별도 생성
public class JpaConfig {

	private final HttpServletRequest httpServletRequest;
	private final JwtProvider jwtProvider;

	@Bean
	public AuditorAware<Long> auditorAware() {
		return () -> {
			String jwtHeader = httpServletRequest.getHeader("Authorization");
			String accessToken = jwtProvider.extractAccessToken(jwtHeader);
			
			return Optional.of(jwtProvider.getMemberId(accessToken));
			
		};
	}
}

 

참고 블로그 : 

https://web-km.tistory.com/42

 

[JPA ] Auditing 기능 살펴보기

Spring Boot 2.4.0 / Spring Data Jpa / JDK 8 / h2database 개요 Auditing 활성화하기 BaseEntity 생성하기 Entity에 적용하기 JUnit으로 테스트해보기 1 @CreatredBy, @ModifiedBy 사용하기 JUnit으로 테스트 해보기 2 실무에서

web-km.tistory.com

 

https://eoneunal.tistory.com/33

 

[Spring Data JPA] JPA Auditing을 이용한 생성/수정 이력 추적

0. 들어가며서비스 운영 시 데이터가 생성되고 수정한 이력을 기록하고 트래킹하는 것은 중요하다. Spring Data JPA에서는 Auditing이라는 기능을 제공한다. 이를 통해 엔티티가 생성되고, 변경되는 시

eoneunal.tistory.com