데이터를 생성하거나 수정할 때, 누가, 언제했는지를 알기 위해 보통 아래와 같은 필드를 각 테이블에 같이 포함 시켜 테이블을 생성합니다.
createdAt (생성일자)modifiedAt (수정일자)createdBy (생성자)modifiedBy (수정자)가장 간단한 방법으로는 생성자 또는 setter 메소드를 활용하여 직접 값을 설정할 수 있습니다.
@Table(name = members)
@Entity
public class Member {
...
@Column
private Datetime createdAt;
@Column
private Datetime modifiedAt;
@Column
private String createdBy;
@Column
private String modifiedBy;
public Member(..., String createdBy, String modifiedBy) {
...
this.createdAt = Datetime.now();
this.modifiedAt = Datetime.now();
this.createdBy = createdBy;
this.modifiedBy = modifiedBy;
}
public modify(..., String modifiedBy) {
...
this.modifiedAt = Datetime.now();
this.modifiedBy = modifiedBy;
}
}
하지만 매번 이렇게 코드를 작성하는 것은 귀찮고 번거롭습니다.
엔티티 객체가 생성이 되거나 변경이 되었을 때 @EnableJpaAuditing 어노테이션을 활용하여 자동으로 값을 등록할 수 있습니다.
@EnableJpaAuditing 어노테이션은 Spring Data 에서 제공하므로 아래처럼 디펜던시를 추가해주어야 합니다..
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}
그리고 Application 클래스에 @EnableJpaAuditing 어노테이션을 추가합니다.
@EnableJpaAuditing // 추가
@SpringBootApplication
public class MyApplication {
...
}
생성일자 와 생성자 를 관리하는 클래스로 BaseEntity 를 생성합니다.
@MappedSuperclass
@EntityListeners(AuditingEntityListener::class)
public abstract class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@CreatedBy
@Column(updatable = false)
private String createdBy;
}
@MappedSuperclass : 공통 맵핑 정보가 필요할 때 사용하며 부모 클래스에서 선언하고 속성만 상속 받아서 사용하고 싶을 때 사용합니다. BaseEntity 를 상속받는 클래스는 모두 createdAt, createdBy 필드가 있어야 합니다.@EntityListeners(AuditingEntityListener::class) : JPA Entity 에 이벤트가 발생할 관련 코드를 실행합니다.@CreatedDate : 생성 일자를 관리하는 필드에 현재 날짜를 주입하는 작업을 수행합니다.@Column(updatable = false) : 생성일자, 생성자에 대한 필드이기 때문에 수정 불가하도록 설정합니다.수정일자 와 수정자 를 관리하는 클래스로 MutableBaseEntity 를 생성합니다.
@MappedSuperclass
@EntityListeners(AuditingEntityListener::class)
public abstract class MutableBaseEntity extends BaseEntity {
@LastModifiedDate
@Column(updatable = true)
private LocalDateTime modifiedAt;
@LastModifiedBy
@Column(updatable = true)
private String modifiedBy;
}
JPA Config. 설정을 따로 해주어야 합니다.
클래스에 @Configuration 어노테이션을 부여함으로써 설정 클래스로 변경하고, @EnableJpaAuditing 어노테이션을 추가해줍니다. 이 이노테이션으로 createdBy, modifiedBy 에 값을 주입할 때는 auditorAwareRef 속성으로 설정하고, createdAt, modifiedAt 에 시간값을 정의할 때에는 dateTimeProviderRef 속성으로 설정할 수 있습니다.
@EnableJpaAuditing(
auditorAwareRef = "principalAuditorAware",
dateTimeProviderRef = "principalAuditorAware"
)
@Configuration
public class JpaAuditConfig {
...
}
이 클래스는 다음과 같이 설정할 수 있습니다.
@Component
public class PrincipalAuditorAware implements AuditorAware<String>, DateTimeProvider {
private final ApplicationContext applicationContext;
public PrincipalAuditorAware(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Optional<TemporalAccessor> getNow() {
return Optional.of(ZonedDateTime.now());
}
@Override
public Optional<String> getCurrentAuditor() {
return Optional.of(applicationContext.getBean(PrincipalProvider.class))
.flatMap(PrincipalProvider::getPrincipal);
}
}
public interface PrincipalProvider {
Optional<String> getPrincipal();
}
public interface AuthenticationHolder {
Optional<Authentication> getAuthentication();
void setAuthentication(Authentication authentication);
}
@Component
public class AuthenticationHolderImpl implements AuthenticationHolder, PrincipalProvider {
private final Authentication authentication;
public AuthenticationHolderImpl(Authentication authentication) {
this.authentication = authentication;
}
@Override
public Optional<Authentication> getAuthentication() {
return Optional.ofNullable(authentication);
}
@Override
public void setAuthentication(Authentication authentication) {
this.authentication = authentication;
}
@Override
public Optional<String> getPrincipal() {
return getAuthentication().map(each -> each.getPrincipal());
}
}
BaseEntity 와 MutableBaseEntity 클래스를 생성한 뒤, 다시 Member 엔티티로 돌아가봅시다.
MutableBaseEntity 를 상속받았기 때문에 createdAt, createdBy, modifiedAt, modifiedBy 과 관련된 코드는 삭제해도 됩니다.
@Table(name = members)
@Entity
public class Member extends MutableBaseEntity {
...
}
@EnableJpaAuditing 어노테이션을 적용하면서 해결해나갔던 이슈들을 정리합니다.
datetime 포맷이 맞지 않다면서 엔티티 저장이 제대로 되지 않았습니다.
아래 글을 참고하여 해결을 했습니다.

https://github.com/spring-projects/spring-boot/issues/10743
@EnableJpaAuditing 에 dateTimeProviderRef 도 있고 auditorAwareRef 라는 속성도 있습니다. 날짜와 관련된 속성은 dateTimeProviderRef 로 설정할 수 있으니 필요하면 꼭 넣어야 합니다.
아래 그림처럼 modifiedAt 이 숫자값으로 표현이 됩니다.

날짜로 표현되어야 하는데 말이죠..
해결하는 방법은 @JsonFormat 을 사용하면 됩니다.

안녕하세요! 글 잘봤습니다! 혹시 마이바티스 사용할때도 createAt, createdBy, modifiedAt, modifiedBy를 디비 테이블 설계시 만들어줘도 괜찮을까요??