JPA Auditing
DB에 데이터를 언제 누가 삽입 혹은 수정을 했는지 기록을 남기는 컬럼이 있는데 JPA의 Auditing을 이용하면 자동으로 기입할 수 있다.
Spring Data Jpa
에서 EntityListener
를 구현한 AuditingEntityListener
가 있다.
@Configurable
public class AuditingEntityListener {
private @Nullable ObjectFactory<AuditingHandler> handler;
public void setAuditingHandler(ObjectFactory<AuditingHandler> auditingHandler) {
Assert.notNull(auditingHandler, "AuditingHandler must not be null!");
this.handler = auditingHandler;
}
@PrePersist
public void touchForCreate(Object target) {
Assert.notNull(target, "Entity must not be null!");
if (handler != null) {
AuditingHandler object = handler.getObject();
if (object != null) {
object.markCreated(target);
}
}
}
@PreUpdate
public void touchForUpdate(Object target) {
Assert.notNull(target, "Entity must not be null!");
if (handler != null) {
AuditingHandler object = handler.getObject();
if (object != null) {
object.markModified(target);
}
}
}
}
코드를 보면 @PrePersist
와 @PreUpdate
애너테이션이 달린 메서드가 있는데, 각각 데이터를 insert 전에 혹은 update 전에 실행되는 메서드이다.
Auditing 을 사용하려면 애플리케이션이 시작할때 @EnableJpaAuditing
를 사용하여 Auditing 을 활성화 주어야한다.
@EnableJpaAuditing
추가하는 방법
@EnableJpaAuditing
를 추가하는 방법은 크게 두가지가 있다.
- SpringApplication 추가하는 방법
@SpringBootApplication
@EnableJpaAuditing
public class SpringApplication {
public static void main(String[] args) {
SpringApplication.run(SpringApplication.class, args);
}
}
애플리케이션이 실행되면서 Auditing이 활성화되고 설정된다. 하지만 이 방법은 테스트 코드에 영향을 줘 테스트가 실패할 수 있다.
- AuditorConfiguation 클래스를 만드는 방법
@EnableJpaAuditing(auditorAwareRef = "customAwareAudit")
@Configuration
public class AuditorConfiguration {
@Bean
public AuditorAware<String> customAwareAudit() {
return new CustomAwareAudit();
}
}
직접 JpaAuditing 설정 클래스를 만들어 활성화 하는 것이다.
이때 생성자와 수정자를 기입해야하는 경우 AuditorAware 인터페이스를 구현해야하는데 이 인터페이스를 구현한 클래스를 Bean으로 등록하여 사용한다.
public class CustomAwareAudit implements AuditorAware<User> {
private final UserRepository userRepository;
@NotNull
@Override
public Optional<User> getCurrentAuditor() {
Authentication authentication = Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
.orElseThrow(() -> new NotLoginException("로그인되지 않았습니다."));
if (!authentication.isAuthenticated()) {
return Optional.empty();
}
User user = (User) authentication.getPrincipal();
return userRepository.findByUsername(user.getUsername());
}
}
AuditorAware 인터페이스에서 오버라이딩한 getCurrentAuditor 메서드의 반환값이 생성자와 수정자로 들어간다고 생각하면 된다.
Repository를 DI 받아 유저정보를 조회해도 되지만 Entity에 변경감지가 일어날 때마다 조회 호출을 해 StackOverFlow 가 발생할 수 있다.
Security에 Authentication 객체를 이용하여 필요한 값을 가질 수 있게 하는 방법으로 해결 할 수 있다.
적용하려면 Entity 클래스위에 @EntityListeners(AuditingEntityListener.class)
애너테이션을 추가하고 생성일, 수정일 칼럼에 각각 @CreatedDate
, @LastModifiedDate
를 추가하면 자동으로 생성일과 수정일이 기입된다.
생성자와 수정자의 경우 각각 @CreatedBy
, @LastModifiedBy
애너테이션을 사용해 자동화할 수 있다.
import java.time.LocalDateTime;
@EntityListeners(AuditingEntityListener.class)
public class Entity() {
@CratedDate
private LocalDateTIme createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
}
@EntityListeners(AuditingEntityListener.class)
public class Entity() {
@CreatedBy
private User createdAt;
@LastModifiedBy
private User updatedAt;
}
생성일, 수정일과 같이 반복되는 코드들은 공통의 클래스로 따로 만들어 상속받아 사용할 수도 있다.
참고
https://gunlog.dev/jpa-auditing#___153
https://gofnrk.tistory.com/59
https://freedeveloper.tistory.com/160
https://web-km.tistory.com/42