JPA entity에 작성자 이름 / 수정자 이름 항목 추가하기 (audit+@)

jaycee·2023년 11월 16일
0
post-thumbnail

goal

jpa 엔티티 생성 시 기존 jpa audit 기능에 작성자 이름과 수정자 이름을 추가한다.

summary

@PrePersist @PreUpdate를 사용한다.
서비스 레이어임에도 불구하고 어쩔 수 없이 http 세션을 사용한다. 개발자는 이러한 사실을 인지하고 있어야한다.

    @PrePersist
    public void prePersistSetCreatorNm(){
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpSession session = servletRequestAttributes.getRequest().getSession();

        LoginInfoModel nowUser = (LoginInfoModel) session.getAttribute("usrInfo");

        if(nowUser == null){
            log.warn("세션 정보가 없습니다.");
            this.setInsertUsrNm("(알 수 없는 사용자)");
            this.setUpdateUsrNm("(알 수 없는 사용자)");
        }else{
            this.setInsertUsrNm(nowUser.getUsrNm());
            this.setUpdateUsrNm(nowUser.getUsrNm());
        }

    }
    
    @PreUpdate
    public void prePersistSetUpdaterNm(){
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpSession session = servletRequestAttributes.getRequest().getSession();

        LoginInfoModel nowUser = (LoginInfoModel) session.getAttribute("usrInfo");

        if(nowUser == null){
            log.warn("세션 정보가 없습니다.");
            this.setUpdateUsrNm("(알 수 없는 사용자)");
        }else{
            this.setUpdateUsrNm(nowUser.getUsrNm());
        }
    }
    

JPA 엔티티에 작성자/수정자 이름을 추가하는 방법

고려할 수 있는 옵션

  • JPA 엔티티를 컨트롤하는 코드에서 매번 작성자와 수정자를 업데이트하는 방법 → 매번 수정자 필드에 대해서 코드를 작성하기 번거롭고 누락할 수도 있다.

  • JPA audit 패키지를 수정하는 방법 → 패키지 분석/수정과 테스트에 공수도 많이 들 뿐더러, JPA 버젼 업그레이드 시 수정한 소스를 계속 같이 업데이트 할 수도 없다.

  • @PrePersist @PreUpdate리스너를 사용하는 방법 → JPA에서 직접 지원하는 어노테이션이기도 하고 한번만 작성해두면 계속해서 반영된다. 이 방법을 사용하기로!

@PrePersist, @PreUpdate란?
영속성 관리에 있어서 PrePersist는 말그대로 영속성에 Persist되기 전, PreUpdate는 영속되어있는 엔티티가 DB에 들어가기 전에 리스너가 이를 감지하여 엔티티 수정을 발생시킨다.
이외에도 아래 그림을 보면 여러가지 영속성 처리 리스너들이 있다.

@PrePersist : 새로운 엔티티에 대해 persist가 호출되기 전
@PreUpdate : 엔티티 업데이트 작업 전
@PreRemove : 엔티티가 제거되기 전
@PostPersist : 새로운 엔티티에 대해 persist가 호출된 후
@PostUpdate : 엔티티가 업데이트된 후
@PostRemove : 엔티티가 삭제된 후
@PostLoad : Select조회가 일어난 직후에 실행

사용자 이름은 어디서 가져오지?

  1. 사용자 이름을 가져오는 방법은 http 세션에서 가져오는 방법과 DB에서 조회해오는 방법이 있다.
  2. 그런데 현재 접속한 사용자의 이름을 가져오려면 어찌됐건 세션에서 가져오는 수밖에 없다.
  3. 왜냐하면 @PrePersist @PreUpdate 리스너 사용 시 별도의 파라미터를 받지 않으므로 현재 사용자를 다른 메소드에서 파라미터로 받을 수가 없다. 즉, http 세션을 이용할 수 밖에 없다.
  4. 세션은 컨트롤러 레이어에서 사용해야 한다. 근데 이 코드를 구현하는 @PrePersist @PreUpdate리스너 위치는 service 레이어이다.
  5. 그러나 서비스 레이어에서는 http 세션 사용을 지양해야한다.
  6. http 세션을 스프링 서비스/리포지토리 레이어에서 사용하는 것은 지양해야 하나, 리스너에서 사용하기 위해선 어쩔 수 없이 http 세션 사용하는 것으로 결정
    *서비스 레이어에서 http 세션 사용 시 기본적으로 테스트가 불가능하기 때문에 세션이 없을 때의 상황도 고려하여 알맞은 처리를 구현해야 한다.

참고

일반적으로 JPA AuditAware 구현 시에도 결국은 세션에서 사용자 ID를 가져온다. 불가피한 부분에 대해서는 사용을 하되, 개발자가 이러한 사용에 대해서 인지하고 있어야하고, 컨트롤 할 수 있어야한다.

@RequiredArgsConstructor
@Component
public class JPALoginUserAuditorAware implements AuditorAware<String> {
    private final HttpSession httpSession;

    @Override
    public Optional<String> getCurrentAuditor() {
        LoginInfoModel nowUser = (LoginInfoModel) httpSession.getAttribute("usrInfo");
        if(nowUser == null)
            return null;

        return Optional.ofNullable(nowUser.getUsrId());
    }
}
profile
오늘도 하나 배웠다.

0개의 댓글

관련 채용 정보