-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BE] createdAt 설정을 위한 BaseEntity 적용 #700
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감자 너무 잘하셨어요! 👍
질문 남겨드렸는데 답변 부탁해요!
@Configuration | ||
@EnableJpaAuditing | ||
public class JpaConfig { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 class는 어떤 용도인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
먼저 @EnableJpaAuditing
애너테이션은 Spring Data Jpa 엔티티의 생성 및 수정 시간을 자동으로 관리하기 위한 감사 기능을 활성화하는 애너테이션 입니다. @CreatedDate
로 엔티티의 생성 날짜 및 시간을 자동으로 설정합니다. @LastModifiedDate
로 엔티티의 수정 날짜 및 시간을 자동으로 업데이트 합니다. 이 애너테이션은 AuditingHandler
및 관련 빈들을 애플리케이션 컨텍스트에 등록하며, JPA 메타 모델을 필요로 합니다.
이 class는 어떤 용도인가요?
@EnableJpaAuditing
애너테이션이 @SpringBootApplication
애너테이션이 붙어있는 HaengdongApplication
클래스에 붙여도 동작합니다. 그렇다면 왜 @EnableJpaAuditing
애너테이션을 별도의 JpaConfig
클래스에 분리하여 붙였을까요?
그 이유는 @SpringBootTest
, @WebMvcTest
애너테이션을 사용하는 테스트에서 @SpringBootApplication
애너테이션을 통해 컴포넌트 스캔하여 컨텍스트를 설정하기 때문입니다. @SpringBootApplication
애너테이션은 @ComponentScan
을 포함하고 있어서 해당 패키지를 포함한 하위 패키지에서 @Component
, @Controller
, @Service
, @Repository
가 붙어있는 클래스들을 빈으로 등록합니다.
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({JpaAuditingRegistrar.class})
public @interface EnableJpaAuditing {
String auditorAwareRef() default "";
boolean setDates() default true;
boolean modifyOnCreate() default true;
String dateTimeProviderRef() default "";
}
@EnableJpaAuditing
애너테이션은 내부적으로 @Import(JpaAuditingRegistrar.class)
를 사용합니다. 이 @Import
애너테이션은 지정된 클래스를 Spring의 ApplicationContext
에 등록하도록 지시합니다. JpaAuditingRegistrar
클래스는 JPA 감사 기능을 설정하는 데 필요한 빈을 등록하는 역할을 합니다. 이 클래스는 @Configuration
애너테이션을 통해 Spring의 설정 클래스로 인식됩니다. @EnableJpaAuditing
이 사용된 클래스가 컴포넌트 스캔의 범위 내에 있으면, Spring Boot는 이 애너테이션을 감지하고 JpaAuditingRegistrar
를 통해 JPA 감사 기능을 설정합니다. 이 과정에서 JpaAuditingHandler
, AuditorAware
, DateTimeProvider
와 같은 관련 빈들이 생성됩니다.
문제는 @WebMvcTest
기반 테스트의 경우 @SpringBootApplication
애너테이션이 붙어있는 클래스를 통해 컨텍스트를 생성하는데, @EnableJpaAuditing
애너테이션이 존재하는 경우 JpaAuditingHandler
빈이 생성되고, 이 빈은 JPA 메타모델에 의존합니다. 하지만 @WebMvcTest
기반 테스트는 Service, Repository와 같은 다른 계층의 빈들은 로드하지 않고 웹 관련 빈들만 로드하기 때문에 JPA 엔티티, Repository 등이 로드되지 않아서 메타 모델이 비어있기 때문에 JPA metamodel must not be empty
에러가 발생합니다.
@WebMvcTest
기반의 테스트를 실행하여 @SpringBootApplication
가 붙어있는 클래스를 찾고 해당 클래스를 기반으로 웹 관련 빈들만 컴포넌트 스캔하여 컨텍스트를 생성하는데, 이전처럼 @SpringBootApplication
과 함께 두어 @EnableJpaAuditing
애너테이션을 스캔하지 않도록 JpaConfig
클래스로 분리하여 JpaAuditingHandler
빈이 생성될 때 JPA 메타 모델을 의존할 수 없어서 발생하는 문제를 막을 수 있습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자세한 설명 감사합니다 👍
@WebMvcTest
에서 빈 주입이 안되는 오류를 막기 위함이었군요. 처음 알았네요!
|
||
@Column(updatable = false) | ||
@CreatedDate | ||
private Instant createdAt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instant는 무엇을 의미하나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instant
는 UTC time-zone을 바탕으로 나노초까지 시간을 나타내는 클래스입니다. 글로벌 서비스인 경우에 여러 지역의 시간을 UTC에 맞게 TimeStamp 형식으로 저장하여 많이 사용합니다.
LocalDateTime
은 시간대가 없이 인스턴스의 TimeZone 기반으로 Offset을 생성 후 현재 시점 기준으로 LocalDate
, LocalTime
객체를 생성하여 로컬 시간에 맞춰서 시간을 나타내는 클래스입니다. TimeZone이 다른 각각의 Region의 서버에서 LocalDateTime.now() 메서드를 사용하면 해당 로컬에 맞는 시간대가 반환됩니다. 단일 리전 서비스인 경우 LocalDateTime
를 사용하는 것이 좋습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UTC 기반 시간이라 지역과 상관없이 적용할 수 있겠군요! 👍
행동대장의 글로벌화를 기원합니다.
import org.springframework.data.jpa.domain.support.AuditingEntityListener; | ||
|
||
@Getter | ||
@EntityListeners(AuditingEntityListener.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EntityListeners는 어떻게 동작하나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EntityListeners
는 JPA에서 엔티티의 생명주기(new, managed, detached, removed) 이벤트에 대한 콜백 메서드(특정 이벤트가 발생할 때 자동으로 호출)를 정의하기 위해 사용되는 애너테이션입니다. 이를 통해 엔티티의 상태 변경 시 특정 로직을 실행할 수 있습니다.
@Entity
@EntityListeners(UserListener.class)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getters and setters
}
public class UserListener {
@PrePersist
public void prePersist(User user) {
// 엔티티가 저장되기 전에 호출되는 메서드
System.out.println("User is about to be persisted: " + user.getName());
}
@PreUpdate
public void preUpdate(User user) {
// 엔티티가 업데이트되기 전에 호출되는 메서드
System.out.println("User is about to be updated: " + user.getName());
}
...
}
@EntityListeners
가 지원하는 주요 생명주기 이벤트
@PrePersist
: 엔티티가 저장되기 전에 호출.@PostPersist
: 엔티티가 저장된 후 호출.@PreUpdate:
엔티티가 업데이트되기 전에 호출.@PostUpdate
: 엔티티가 업데이트된 후 호출.@PreRemove
: 엔티티가 삭제되기 전에 호출.@PostRemove
: 엔티티가 삭제된 후 호출.@PostLoad
: 엔티티가 로드된 후 호출.
@EntityListeners
는 엔티티에 생명주기 이벤트에 따라 Listener
에 정의된 콜백 메서드를 수행합니다.
AuditingEntityListener
는 Spring Data JPA가 제공하는 기본 리스너로, 엔티티의 생성 및 수정 시각과 관련한 필드를 자동으로 처리합니다. 이를 위해서 @EnableJpaAuditing
애너테이션을 사용하여 JPA 감사 기능을 활성화해야 합니다.
위 코드에서는 BaseEntity
에 감사 필드를 정의하고, JPA 엔티티의 생명주기 이벤트에 따라 엔티티가 생성(@CreatedDate
), 수정(@LastModifiedDate
) 이벤트가 발생할 때 현재 시간이 자동으로 설정됩니다. BaseEntity
엔티티는 단독으로 생성하여 사용하지 않고, 다른 도메인 엔티티들이 상속받아서 엔티티 생명주기 이벤트가 발생할 때 자동으로 현재 시간을 설정할 수 있도록 도와주는 시스템 컬럼으로써 역할을 합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오!
이 어노테이션으로 엔티티의 상태 변화를 명확하게 파악하기 좋겠네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이상 자세한 설명 감사해요! 도움이 많이 됐어요!
* fix: CI/CD 스크립트 정상화 (#706) * feat: workflow 복구 * test: dev 워크플로우 테스트 * test: 잘못된 yaml 형식 수정 * test: 설정 서브모듈 추가 * fix: eof 추가 * feat: 이미지 업로드 경로 업데이트 * feat: 은행 이름 수정 (#712) * feat: BaseEntity 적용 (#700) * feat: 영수증 이미지 업로드 기능 추가 (#714) * feat: gitignore 추가 * feat: 이미지 업로드/다운로드 기능 추가 * feat: 이미지 업로드/다운로드 기능 추가 * feat: 운영, 개발 image 설정 분리 * feat: 서브모듈 삭제 * test: imageUploadService 추가 * test: 행사 이미지 저장 및 조회 기능 테스트 * feat: 이미지 삭제 기능 구현 * test: 이미지 삭제 테스트 추가 --------- Co-authored-by: juha <[email protected]> * docs: adoc 수정 (#722) * chore: 테스트용 트리거 브랜치 삭제 (#726) --------- Co-authored-by: juha <[email protected]> Co-authored-by: Arachne <[email protected]> Co-authored-by: juha <[email protected]>
issue
구현 사항
createdAt 설정을 위해 BaseEntity를 추가했습니다.