Programming/JPA

JPA Auditing

잇나우 2021. 8. 5. 20:35
반응형

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를 추가하는 방법은 크게 두가지가 있다.

  1. SpringApplication 추가하는 방법
@SpringBootApplication
@EnableJpaAuditing
public class SpringApplication {

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

애플리케이션이 실행되면서 Auditing이 활성화되고 설정된다. 하지만 이 방법은 테스트 코드에 영향을 줘 테스트가 실패할 수 있다.

  1. 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

반응형