자바 심화 2기

2024 11 11 TIL - AuditorAware 구현하기

Griotold 2024. 11. 11. 18:59

1. 문제 상황

배달 앱을 만드는 팀프로젝트 중 요구사항으로

모든 테이블에 생성한 사람, 생성날짜, 업데이트한 사람, 업데이트날짜를 기록하라는 것이 있었다.

이것을 구현하기 위해 JpaAuditing, AuditorAware를 활용하여 통해,

해당 테이블에 변경사항이 있을 시 현재 로그인 중인 사용자의 id를 자동으로 기록되도록 구현하려고 했다.

참고한 자료는 아래 블로그 글이다.

https://javacpro.tistory.com/85

 

[Spring Boot] JPA, AuditorAware 사용하여 사용자정보 자동 입력

1. Config 생성 @EnableJpaAuditing 어노테이션을 추가하여 Annotation 을 사용하여 Audit 활성화 @Configuration @EnableJpaAuditing public class JpaAuditConfig { @Bean public AuditorAware auditorProvider() { return new AuditorAwareImpl(); } }

javacpro.tistory.com

문제는 AuditorAware 기능을 추가한 후, 

원래는 잘 되던 결제 요청 API가 먹히지 않는 것이었다.

 

2. 원인 파악

참고한 블로그 글에서는 createdBy 와 updatedBy 가 Long 타입으로 선언되어 있었다.

userId가 들어가기 때문에 Long 타입으로 선언한 것 같고

userId가 데이터베이스에서 자동으로 채번이 되는 값,

MySQL로 예를 들면 Auto Increment 로 만들어지는 값으로 판단된다.

 

우리 팀 프로젝트도 MySQL은 아니지만, 동일하게 데이터베이스에서 자동으로 채번해주는 값,

Long 타입이 들어가기 때문에 동일하게 구현해줬던 것이다.

하지만, 우리 팀의 BaseEntity를 확인해보니 createdBy 와 updatedBy가 String으로 선언되어 있었다.

 

// 블로그의 BaseEntity

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public abstract class BaseEntity {

    ...

    //등록자
    @CreatedBy
    @Column(updatable = false)
    protected Long createBy;

    //수정자
    @LastModifiedBy
    protected Long lastModifedBy;

}
출처: https://javacpro.tistory.com/85 [버물리의 IT공부:티스토리]

// 우리 팀의 BaseEntity
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public abstract class BaseEntity {

    ...

    //등록자
    @CreatedBy
    @Column(updatable = false)
    protected String createBy;

    //수정자
    @LastModifiedBy
    protected String lastModifedBy;

}

 

따라서, 결제 요청 API를 호출했을 때, 결제 테이블에 데이터가 남는 순간 createdBy 와 updatedBy가 자동으로 기록되어야 하는데 Long -> String 타입 변환이 안되니, API가 실패가 나는 것이었다.

 

3. 해결 방법

블로그에서는 AuditorAware<Long> 으로 제네릭을 Long으로 잡아주고 있으므로,

우리는 우리 팀 프로젝트에 맞게 AuditorAware<String> 으로 제네릭을 잡아주면, 간단히 해결될 것이다.

// 참고한 블로그 코드
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;

public class AuditorAwareImpl implements AuditorAware<Long> {

    @Override
    public Optional<Long> getCurrentAuditor() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if(null == authentication || !authentication.isAuthenticated()) {
            return null;
        }

		//사용자 환경에 맞게 로그인한 사용자의 정보를 불러온다. 
        CustomUserDetails userDetails = (CustomUserDetails)authentication.getPrincipal();

        return Optional.of(userDetails.getId());
    }

}
출처: https://javacpro.tistory.com/85 [버물리의 IT공부:티스토리]


// 우리 팀 프로젝트에 적용한 코드
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.Optional;

public class AuditorAwareImpl implements AuditorAware<String> {

	...
}

 

4. 결과

created_by 와 updated_by가 정확하게 요청한 userId가 들어가고 있음을 확인할 수 있었다.