BE/스프링
JPA Auditing
sonoopy
2024. 11. 14. 17:35
JPA Auditing이란?
엔티티의 생성, 수정과 관련된 메타 데이터를 자동으로 관리하기 위한 기능
예를 들어, 엔티티가 생성된 시각, 마지막으로 수정된 시각, 생성한 사용자, 수정한 사용자 등의 정보를 데이터베이스에 자동으로 기록
- 데이터가 변경되는 시점 감지
- 데이터 변경 시 자동으로 이력 기록 (created_at, created_by...)
- 엔티티 클래스에 어노테이션 추가하여 사용
1. Gradle에 의존성 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}
2. Spring Boot 애플리케이션 @EnableJpaAuditing 추가
@SpringBootApplication
@EnableJpaAuditing
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
또는 별도의 설정 클래스를 생성
@Configuration
@EnableJpaAuditing
public class JpaAuditingConfig {
}
3. Base Entity 생성
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
@CreatedBy
private String createdBy;
@LastModifiedBy
private String updatedBy;
}
4. AuditorAware 구현
: @CreatedBy와 @LastModifiedBy를 사용하려면 현재 사용자를 반환하는 AuditorAware 구현체를 생성
AuditorAware<T>는 JPA Auditing 기능에서 현재 감사 주체(Auditor)를 제공하기 위한 인터페이스
Spring Security 연동 : 인증된 사용자 이름 반환
@Component("auditorProvider")
public class SecurityAuditorAware implements AuditorAware<String> {
@Override
public Optional<String> getCurrentAuditor() {
// Spring Security에서 현재 인증 정보 가져오기
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 인증 정보가 없거나 인증되지 않은 경우
if (authentication == null || !authentication.isAuthenticated()) {
return Optional.empty();
}
// 인증된 사용자의 이름 반환
return Optional.of(authentication.getName());
}
}
추가 정보(예: 이메일, 사용자 ID)를 반환하려면,
Custom Principal 사용
Spring Security에서 사용자 정보를 UserDetails 구현체로 커스터마이징한 경우, Principal 객체에서 정보를 가져올 수 있음
@Override
public Optional<String> getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return Optional.empty();
}
Object principal = authentication.getPrincipal();
if (principal instanceof CustomUserDetails) {
CustomUserDetails userDetails = (CustomUserDetails) principal;
return Optional.of(userDetails.getEmail()); // 사용자 이메일 반환
}
return Optional.empty(); // Principal이 CustomUserDetails가 아닌 경우
}
Custom Principal은 Spring Security의 Authentication 객체에 사용자 정의 정보 포함 가능
-> 인증 프로세스에서 Principal로 사용자 객체(UserDetails 구현체 등)를 설정하는 방식
5. 엔티티에서 BaseEntity를 상속받아 Auditing 필드 포함
@Getter
@NoArgsConstructor
@Entity
public class User extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
}