jpa 엔티티 생성 시 기존 jpa audit 기능에 작성자 이름과 수정자 이름을 추가한다.
@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 audit 패키지를 수정하는 방법 → 패키지 분석/수정과 테스트에 공수도 많이 들 뿐더러, JPA 버젼 업그레이드 시 수정한 소스를 계속 같이 업데이트 할 수도 없다.
@PrePersist
@PreUpdate
리스너를 사용하는 방법 → JPA에서 직접 지원하는 어노테이션이기도 하고 한번만 작성해두면 계속해서 반영된다. 이 방법을 사용하기로!
@PrePersist, @PreUpdate란?
영속성 관리에 있어서 PrePersist는 말그대로 영속성에 Persist되기 전, PreUpdate는 영속되어있는 엔티티가 DB에 들어가기 전에 리스너가 이를 감지하여 엔티티 수정을 발생시킨다.
이외에도 아래 그림을 보면 여러가지 영속성 처리 리스너들이 있다.
@PrePersist : 새로운 엔티티에 대해 persist가 호출되기 전
@PreUpdate : 엔티티 업데이트 작업 전
@PreRemove : 엔티티가 제거되기 전
@PostPersist : 새로운 엔티티에 대해 persist가 호출된 후
@PostUpdate : 엔티티가 업데이트된 후
@PostRemove : 엔티티가 삭제된 후
@PostLoad : Select조회가 일어난 직후에 실행
@PrePersist
@PreUpdate
리스너 사용 시 별도의 파라미터를 받지 않으므로 현재 사용자를 다른 메소드에서 파라미터로 받을 수가 없다. 즉, http 세션을 이용할 수 밖에 없다.@PrePersist
@PreUpdate
리스너 위치는 service 레이어이다. 일반적으로 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());
}
}