데이터를 생성하거나 수정할 때, 누가, 언제했는지를 알기 위해 보통 아래와 같은 필드를 각 테이블에 같이 포함 시켜 테이블을 생성합니다.
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를 디비 테이블 설계시 만들어줘도 괜찮을까요??