Auditing
테이블을 설계할 때, 공통적으로 들어가는 컬럼이있는데, 바로
생성일자,수정일자,생성자,수정자 이다.
거의 모든 테이블에 들어가있고 정렬, 필터, 또는 검증? 도 할 수 있는 꽤나 중요한 정보들이다.
하지만 서비스를 요청을 하거나 응답을 줄 때, 필요한 정보가 아니기도하다. 서비스에는 영향이없지만 필요하고 중요한? 데이터를
spring-data-jpa 모듈에서 자동으로 넣을 수 있도록 제공을해준다.
해당 기능이 바로 Auditing이다.
사용하기
1. Main App 클래스에 @EnableJpaAuditing 추가하기
@EnableJpaAuditing
@SpringBootApplication
public class Application {
2. 엔티티 클래스 위에 @EntityListeners (AuditingEntityListener.class) 추가
@Getter
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class BaseEntity {
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
@CreatedDate
@Column(nullable = false, updatable = false)
protected LocalDateTime createdDateTime; // 생성일시
@CreatedBy
@Column(nullable = false, updatable = false, length = 100)
protected String createdBy; // 생성자
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
@LastModifiedDate
@Column(nullable = false)
protected LocalDateTime modifiedDateTime; // 수정일시
@LastModifiedBy
@Column(nullable = false, length = 100)
protected String modifiedBy; // 수정자
3. AuditorAware 구현체 정의하기
@CreatedBy(생성자), @ModifiedBy(수정자)의 경우 별도의 구현체를 통해 정보를 가져와야합니다.
해당 과정에서 Spring Security 설정이 필요합니다.
저의 경우에는 Jwt 인증 방식으로 구현했기에 토큰 검증을 하는 Filter에서 검증 후 SecurityContextHolder에 인증정보를 넣어줍니다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String accessToken = jwtProvider.resolveToken(request);
if (accessToken != null && jwtProvider.validateAccessToken(accessToken)) {
log.debug("access user");
// check access token
AbstractAuthenticationToken auth = (AbstractAuthenticationToken) jwtProvider.getAuthenticationByAccessToken(accessToken);
//인증정보 set
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
저장된 인증정보에서 Id값을 가져와 반환합니다.
@Component
public class AuditingConfig implements AuditorAware<String>{
@Override
public Optional<String> getCurrentAuditor() {
//SecurityContextHolder에 저장된 인증정보 가져오기
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//인증이 안되있거나 익명인 경우 빈값 반환
if (null == authentication || !authentication.isAuthenticated() || "anonymousUser".equals(authentication.getPrincipal())) {
return Optional.empty();
}
//인증된 유저 정보 가지요기
UserDetails user = (UserDetails) authentication.getPrincipal();
//유저 Id 반환
return Optional.ofNullable(user.getUsername());
}
}
※ @MappedSuperclass
- 일반적으로, 상속 관계 매핑 전략에서 부모 클래스와 자식 클래스 모두 DB 테이블과 매핑을 한다.
- 이와 달리, 부모 클래스를 상속받는 자식클래스에게
🔑 매핑 정보 속성만 제공하고 싶을때 이 어노테이션을 사용하면 된다. - 엔티티 종류에 상관없이 공통으로 가지고 있어야 하는 정보가 있다면 ( ex. 생성시간, 수정시간 등 ) 공통 클래스로 추출하고 이를 상속받는 방식으로 구현할 때 사용 한다.
DB 테이블과는 상관없다. 아래에 보면 DB는 매핑 정보 다 따로 쓰고 있다. 객체의 입장이다. - 그러나 엔티티는 엔티티만 상속받을 수 있기 때문에 엔티티가 아닌 클래스를 상속받기 위해서 @MappedSuperclass 를 사용한다.
Reference
- https://feco.tistory.com/13 (MappedSuperClass)
- https://velog.io/@wonizizi99/SpringData-JPA-Auditing (Auditing)
728x90
'프로그래밍 > Spring' 카테고리의 다른 글
[Spring] 유효성 검증 - Validation (0) | 2023.11.13 |
---|---|
[Spring] REST API 테스트 코드 작성하기 (0) | 2023.11.06 |
[Spring] 테스트 코드에서 JPA metamodel must not be empty! 예외가 발생할 때 (0) | 2023.11.04 |
[Spring] 어노테이션 장점과 @Autowired 이용한 DI (0) | 2022.07.24 |
[Spring] DI 지시서 작성 (Spring Bean Configuration) (0) | 2022.07.24 |