1. 문제 상황
Spring Boot와 JPA를 사용하면서, 여러 엔티티 클래스에 동일한 코드를 반복해서 작성해야 하는 문제가 생겼습니다. 제가 생각한 중복 코드의 문제점은 아래와 같습니다.
중복 코드의 문제점:
- 코드 가독성이 떨어지고 관리가 어려움.
- 공통 기능을 수정할 경우, 모든 엔티티 클래스를 일일이 수정해야 함.
- 유지보수 시 실수 가능성이 증가.
2. 해결 방법
JPA의 상속과 Spring Data JPA Auditing 기능을 사용하면, 이런 중복을 한 번에 해결할 수 있었습니다. 상속을 통해 공통된 필드를 부모 클래스에 작성하고, 이를 상속받는 방식으로 재사용하면 됩니다.
3. 해결 과정
1) 상속 클래스(BaseTimeEntity) 만들기
엔티티 클래스의 공통 필드를 포함하는 부모 클래스를 만들어 볼게요. 이 클래스는 실제로 테이블에 매핑되지 않으며, 자식 클래스가 상속받아 사용할 수 있도록 설계합니다.
@Getter
@MappedSuperclass // 부모 클래스를 엔티티로 매핑하지 않고 자식 클래스에 필드만 추가
@EntityListeners(AuditingEntityListener.class) // JPA Auditing 활성화
public abstract class BaseTimeEntity {
@CreatedDate // 엔티티가 처음 저장될 때 생성 시간 자동 저장
private LocalDateTime createdDate;
@LastModifiedDate // 엔티티가 수정될 때 마지막 수정 시간 자동 저장
private LocalDateTime modifiedDate;
}
여기서 어노테이션 설명:
- @MappedSuperclass: 이 클래스를 상속받는 엔티티 클래스의 테이블에 필드가 추가되도록 설정합니다.
- @EntityListeners(AuditingEntityListener.class): Spring Data JPA의 감시/감사(Auditing) 기능을 활성화합니다.
- @CreatedDate: 처음 저장되는 시점의 시간을 자동으로 기록합니다.
- @LastModifiedDate: 마지막으로 수정된 시점의 시간을 자동으로 기록합니다.
2) 엔티티 클래스에서 상속받기
이제 엔티티 클래스는 공통 필드를 상속받기만 하면 됩니다. User와 Post를 다시 작성해 볼겠습니다.
@Entity
public class User extends BaseTimeEntity { // 공통 필드 상속
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
@Entity
public class Post extends BaseTimeEntity { // 공통 필드 상속
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String content;
}
변화:
- 공통되는 부분인 createdAt 필드를 제거 했습니다.
- 이제 이런 공통 필드는 부모 클래스인 BaseTimeEntity에서 관리가 됩니다.
3) Auditing 기능 활성화
Spring Data JPA의 Auditing 기능을 활성화하려면 메인 클래스에 @EnableJpaAuditing을 추가해야 합니다.
@SpringBootApplication
@EnableJpaAuditing // JPA Auditing 활성화
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. 적용 결과 확인
실제 동작 예시
엔티티를 저장하거나 수정하면, createdDate와 modifiedDate 필드가 자동으로 설정됩니다. 테스트 코드를 작성해서 확인해 볼겠습니다.
@SpringBootTest
class BaseTimeEntityTest {
@Autowired
private UserRepository userRepository;
@Test
void testBaseTimeEntity() {
// 엔티티 저장
User user = new User();
user.setName("John Doe");
userRepository.save(user);
// 저장된 엔티티 확인
User savedUser = userRepository.findById(user.getId()).orElseThrow();
System.out.println("Created Date: " + savedUser.getCreatedDate()); // 저장 시간 출력
System.out.println("Modified Date: " + savedUser.getModifiedDate()); // 저장 시간 출력
// 엔티티 수정
savedUser.setName("Jane Doe");
userRepository.save(savedUser);
// 수정된 엔티티 확인
User updatedUser = userRepository.findById(savedUser.getId()).orElseThrow();
System.out.println("Modified Date: " + updatedUser.getModifiedDate()); // 수정 시간 갱신 확인
}
}
결과
- 저장 시간: createdDate가 저장된 시점으로 기록됩니다.
- 수정 시간: modifiedDate가 수정된 시점으로 갱신됩니다.
5. 이 방식을 사용하며 배운 점
- 중복 코드 제거
- 여러 엔티티에서 반복적으로 작성하던 코드를 제거했어요.
- 유지보수 용이
- 공통 필드를 한 곳에서 관리하니 수정과 유지보수가 훨씬 쉬워졌어요.
- 확장 가능성
- 만약 작성자(createdBy)나 수정자(modifiedBy)와 같은 추가 필드가 필요하다면 BaseTimeEntity에만 추가하면 됩니다.
6. 주의사항
- @EnableJpaAuditing 어노테이션을 꼭 활성화해야 @CreatedDate와 @LastModifiedDate가 동작합니다.
- 모든 엔티티가 BaseTimeEntity를 상속받을 필요는 없습니다. 특정 엔티티에만 적용하려면 별도로 설계하세요.
마무리
이번 글에서는 JPA 상속 클래스를 사용해 엔티티 클래스의 중복 코드를 제거하는 방법을 알아봤어요. 이러한 방식은 엔티티의 공통 필드를 효율적으로 관리하고, 유지보수를 쉽게 할 수 있다는 장점이 있습니다. 다음에도 이런 문제를 만난다면 꼭 상속과 Auditing을 활용해 보세요! 😊
'문제 및 해결' 카테고리의 다른 글
[Spring JPA] 영속성 동작하지 않을 때의 원인과 해결법 (0) | 2024.12.16 |
---|---|
[VUE] 카카오 맵 api... 로딩 안되는 문제 해결 (0) | 2024.12.07 |
JavaScript에서 console.log에 객체를 출력하면 [object Object]로 표시 될 때 (0) | 2024.12.07 |
@PrePersist를 활용한 엔티티 초기화: 생성일자 처리 방법 (0) | 2024.11.26 |
이미지가 많아져서 웹사이트가 느리다면?? (2) | 2024.11.14 |