민우의 코딩일지
article thumbnail

 

 

JPA  Auditing

 

 

소개

 

데이터를 추가, 수정시 자동으로 등록 및 수정 일시를 기록해주는 기능을 지원해준다

뿐만아니라 AuditorAware 인터페이스 상속을통해 등록 및 수정 유저명까지 기록해주는 기능을 이용할 수 있다.

 

 

auditing 단어 뜻

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

사전 준비

 

MainApplication 클래스 파일에 어노테이션 추가

 

다음 @EnableJpaAuditing 어노테이션을 추가해주었다

 

 

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing // <= 새로 추가한 어노테이션
@SpringBootApplication
public class MainApplication {
	public static void main(String[] args) {
		SpringApplication.run(MainApplication.class, args);
	}
}

 

 

 

 

 

 

 

 

 

 

AuditorAware 인터페이스 상속받아  getCurrentAuditor() 메소드 오버라이딩 해주기

 

엔티티 파일에서 다음 2가지 어노테이션 @CreatedBy , @LastModifiedBy 사용시, 자동으로 저장될 값을  다음과 같은 방법으로 설정해줄 수 있다.

 

return 객체는 Optional<String> 타입의 로그인 아이디여야한다.

따라서, 스프링시큐리티 컨텍스트에서 가져온 값을 사용하는것이 좋다.

* 하지만, 테스트 확인을 위해 하드코딩된 문자열을 리턴해줌으로써, 작성자 및 수정자엔 테스트용이 입력되게된다.

 

 

import org.springframework.data.domain.AuditorAware;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
public class UserAuditorAwareConfig implements AuditorAware<String> {

    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("테스트용"); // 테스트용 문자열을 Optional<String>  타입으로 변환하여 리턴
        
        /* 
            테스트용으로 return Optional.of("테스트용"); 코드를 사용했으나
            실제로는 return SecurityUtil.getUsername(); 처럼 시큐리티 컨텍스트에서 가져온 값을 리턴해야한다
        */
        
    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

사용 예시

 

파일 수정 : 사용중인 엔티티 클래스 파일

 

클래스명 위에 @EntityListeners(AuditingEntityListener.class) 어노테이션을 추가해주고

마지막으로 클래스 필드에는 다음 내용을 추가해주면 끝이다 👏

 

 

 

 

 

 

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
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 java.util.Date;

@Entity
@Getter
@Setter
@Table(name ="board")
@EntityListeners(AuditingEntityListener.class) // <= 새로 추가한 어노테이션
public class BoardEntity  {

    /*  ...


    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	private Long uid;
        
        .. 등등
        
        ... 기존 내용은 생략 ...

        ...  */

    @CreatedDate
    @Column(name="created_date")
    private Date createdDate; // 작성 일시

    @CreatedBy
    @Column(name="created_by")
    private String createdBy; // 작성자

    @LastModifiedDate
    @Column(name = "modified_date")
    private Date modifiedDate; // 수정 일시

    @LastModifiedBy
    @Column(name = "modified_by")
    private String modifiedBy; // 수정자

}

 

 

 

 

 

 

 

 

 

 

 

 


 

 

성능 개선 : @MappedSuperclass 어노테이션 이용하기

 

등록 및 수정일시, 그리고 각 유저명 필드는 게시판, 댓글 등 .. 다양한 엔티티에서 사용된다.

따라서, 해당 필드 내용을 별도의 클래스로 따로 만들고 필요한 엔티티에서 상속받아 이용하는 방식으로 개선할 수 있다.

 

클래스 상속으로 엔티티 필드에 추가하려면,  상속 받을 클래스에서 @MappedSuperclass 어노테이션을 이용해주면 된다.

 

 

 

등록일시 및 유저명만 기록하는 클래스 파일

 

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.util.Date;

@Getter
@MappedSuperclass // <= 엔티티에 상속받았을때, 해당 필드로 컬럼이 생성 되도록
@EntityListeners(AuditingEntityListener.class) // <= 자동 기록을 위해 
public class CreatedInfo {

    @CreatedDate
    @Column(name="created_date")
    private Date createdDate;

    @CreatedBy
    @Column(name="created_by")
    private String createdBy;
    
}

 

 

 

그리고,  수정일시 및 유저명까지 기록하는 클래스 파일

 

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.util.Date;

@Getter
@MappedSuperclass // <= 엔티티에 상속받았을때, 해당 필드로 컬럼이 생성 되도록
@EntityListeners(AuditingEntityListener.class) // <= 자동 기록을 위해 
public class ModifiedInfo extends createdInfo {

    @LastModifiedDate
    @Column(name = "modified_date")
    private Date modifiedDate;

    @LastModifiedBy
    @Column(name = "modified_by")
    private String modifiedBy;    

}

 

 

 

 

 

 

 

파일 수정 : 사용중인 엔티티 클래스 파일

 

ModifiedInfo 클래스를 상속받으면,  수정 일시 및 유저명이 엔티티 필드에 추가된다.

그런데, 해당 클래스가 CreatedInfo 클래스를 상속받고 있기때문에  작성 일시 및 유저명도 함께 추가된다.

 

결과적으로 작성 및 수정 일시, 그리고 유저명이 기록되어야하는 엔티티는 ModifiedInfo 클래스를 상속받으면 된다.

만약  수정이 불가하고, 등록만 가능한 엔티티는 CreatedInfo  클래스를 상속받으면 된다.

 

자주 사용되는 필드를 @MappedSuperclass 어노테이션을 이용해 클래스로 빼고,

상황에 맞는 클래스를 상속받아 사용하도록 성능 개선을 할 수 있었다 👍

 


@Entity
@Getter
@Setter
@Table(name ="board")
// 클래스 상속으로 해당 어노테이션 필요 X  ->  @EntityListeners(AuditingEntityListener.class)

public class BoardEntity extends ModifiedInfo  {

    /*  ...


    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	private Long uid;
        
        .. 등등
        
        ... 기존 내용은 생략 ...



    @CreatedDate
    @Column(name="created_date")
    private Date createdDate; // 작성 일시

    @CreatedBy
    @Column(name="created_by")
    private String createdBy; // 작성자

    @LastModifiedDate
    @Column(name = "modified_date")
    private Date modifiedDate; // 수정 일시

    @LastModifiedBy
    @Column(name = "modified_by")
    private String modifiedBy; // 수정자
    
    
    
    
    ... 위 작성 및 수정일시 , 그리고 유저명도 클래스 상속으로 해결되었기때문에 주석 처리 ...
    
    
        ...  */    

}