민우의 코딩일지
article thumbnail

 

 

1. JPA  Auditing

 

 

1.1. 소개

 

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

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

 

 

auditing 단어 뜻

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

1.2. 사전 준비

 

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

 

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

 

 

<java />
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); } }

 

 

 

 

 

 

 

 

 

 

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

 

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

 

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

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

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

 

 

<java />
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(); 처럼 시큐리티 컨텍스트에서 가져온 값을 리턴해야한다 */ } }

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

1.3. 사용 예시

 

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

 

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

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

 

 

 

 

 

 

<java />
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; // 수정자 }

 

 

 

 

 

 

 

 

 

 

 

 


 

 

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

 

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

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

 

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

 

 

 

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

 

<java />
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; }

 

 

 

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

 

<java />
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; }

 

 

 

 

 

 

 

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

 

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

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

 

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

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

 

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

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

 

<java />
@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; // 수정자 ... 위 작성 및 수정일시 , 그리고 유저명도 클래스 상속으로 해결되었기때문에 주석 처리 ... ... */ }