JPA를 사용해서 엔티티에 생성되어있는 created_at과 updated_at의 중복 코드를 줄여보도록 하자
내가 진행하고 있는 프로젝트에서 기존의 Entity들은 아래 코드처럼 컬럼이 정의되어 있었다.
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt
그리고 엔티티들이 생성될 때, 나는 각각 생성자에 LocalDateTime.now()를 통해 DB에 저장시켜줬다.
@Builder
public Answer(String content, Integer emotion, LocalDate date, User user, Boolean isPublic, Boolean isPremium, Boolean isSpare){
this.content = content;
this.emotion = emotion;
this.date = date;
this.isPublic = isPublic;
this.isPremium = isPremium;
this.createdAt = LocalDateTime.now();
this.user = user;
this.isBlind = false;
this.likeCount = 0;
this.isSpare = isSpare;
}
이렇게 코드를 짜면 무엇이 문제일까?
개발자도 사람이다보니, 각 생성자마다 this.createdAt를 붙이는 과정에서 실수가 날 수 있고 엔티티가 여러개인 상황에서는 '중복 코드'가 생길 수 밖에 없다. 이는 객체지향적으로 코드를 짜지 않는 것이고 불필요한 코드를 남발하는 개발인 것이다.
이를 위해 JPA에서는 모든 Entity의 상위 클래스에서 createdAt, updatedAt를 자동으로 관리해주는 역할을 제공해주고 있다.
우선, 메인 클래스에서 @EnableJpaAuditng이라는 어노테이션을 붙여주도록 하자.
@SpringBootApplication
@EnableScheduling
@EnableJpaAuditing
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
@PostConstruct
public void setTime() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
}
}
나는 DB에 UST로 저장되는 것이 아닌, KST로 저장받고 싶어 @PostConstruct를 통해 전역 타임존을 서울 시간으로 맞췄다. @EnableJpaAuditing을 붙여줌으로써 이제 JPA에서 자동으로 Auditing을 관리해주는 것이다.
그리고 이제 엔티티들을 상위에서 관리해줄 추상 클래스를 만들어주도록 하자.
@Getter
@MappedSuperclass // 추후에 BaseTimeEntity를 상속한 엔티티들을 아래 필드들을 컬럼으로 인식
@EntityListeners(AuditingEntityListener.class) // Auditing(자동으로 값 매핑) 기능 추가
public abstract class BaseTimeEntity {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
}
위 코드를 보면 추상클래스로 BaseTimeEntity를 만들어줬다.
처음보는 어노테이션들이 있는데 하나씩 보도록 해보자
@MappedSuperClass : 앞서 말한대로 우리는 기존에 사용되고 있던 엔티티들을 상위에서 시간들을 자동으로 관리해준다고 했었다. 그러면 예를 들어 Answer 클래스에서 기존에 사용되고 있던 created_at, updated_at 같은 컬럼이 남아있으면 관리가 힘들 수도 있겠다. 그래서 우리는 Answer 클래스에서 created_at, updated_at을 없애고 BaseTimeEntity에서 이들을 정의해주며 상위에서 관리한다는 것이다. 즉, @MappedSuperClass는 추후 BaseTimeEntity를 상속한 엔티티들(ex.. Answer)을 아래 필드들(created_at, updated_at)을 컬럼으로 인식하라 라는 의미이다. 이 어노테이션을 붙임으로써 상속한 모든 클래스에서 불필요한 컬럼 정의 코드를 없앨 수 있다.
@EntityListeners(AuditingEntityListener.class) : @EntityListeners 어노테이션은 특정 엔티티에 대한 이벤트 리스너 클래스를 등록하는데 사용된다. AuditingEntityListener 클래스는 주로 Jpa 엔티티에 대한 Auditing 정보를 자동으로 처리하는데 사용된다. 이 클래스를 사용하면 엔티티가 생성 또는 업데이트 될 때 자동으로 갱신이 가능하다. 즉, 이 어노테이션을 사용함으로써 모든 클래스에서 컬럼 생성 및 수정에 사용되었던 (ex.. this.createdAt = LocalDateTime.now()) 같은 코드들을 없앨 수 있다는 것이다.
@CreatedDate, @LastModifiedDate : 이 어노테이션은 이름으로 알 수 있듯이, 엔티티가 생성, 마지막으로 수정되는 시간을 의미한다.
이제 모든 학습이 끝났다. 어떻게 코드가 줄어드는지 보도록 하자.
방금 Answer 클래스를 보도록 하자.
@Table(name = "answer")
@Entity
@Getter
@NoArgsConstructor
public class Answer extends BaseTimeEntity {
// Codes
}
기존의 Answer 클래스와 다르게 BaseTimeEntity를 상속(extends)하는 모습이다. 또 코드에는 안나와있지만 기존에 정의되어있던
@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt
같은 코드도 삭제했다. 또
@Builder
public Answer(String content, Integer emotion, LocalDate date, User user, Boolean isPublic, Boolean isPremium, Boolean isSpare){
this.content = content;
this.emotion = emotion;
this.date = date;
this.isPublic = isPublic;
this.isPremium = isPremium;
// this.createdAt = LocalDateTime.now();
this.user = user;
this.isBlind = false;
this.likeCount = 0;
this.isSpare = isSpare;
}
기존 코드와는 다르게 더이상 createdAt을 수동으로 관리하지 않는다. 코드로는 못보여주고 있지만 updated_at도 마찬가지이다. 엔티티를 수정하는 비즈니스 로직에 쓰이면 매우 유용할 것이다.
지금은 Answer 클래스 하나만 예시로 보여줬지만, 실제로 내가 하고 있는 프로젝트에서는 상당히 많은 엔티티들이 created_at과 updated_at이 쓰이고 있다. 이들 모두 BaseTimeEntity를 통해 상속받게하고 관리해주며 이득을 볼 것이다.
'구현' 카테고리의 다른 글
[구현] 싱글톤(Singleton) 패턴 직접 적용해보기 (0) | 2023.12.06 |
---|---|
[구현] 애플 소셜로그인 탈퇴 / SpringBoot (0) | 2023.07.28 |
[구현] 푸시알림(FCM) / SpringBoot (0) | 2023.06.17 |