3 분 소요

0. 개요

  • Envers 모듈은 하이버네이트 및 JPA와 함께 작동하는 핵심 모듈.

  • 엔티티 클래스를 위한 쉬운 감사 & 버전관리 솔루션 제공.

    • JPA 스팩에 정의 된 모든 매핑 감사

    • 엔티티의 변경 이력을 자동 관리

    • 트랜잭션 단위의 통합 Revision 관리(Snapshot)

1. 의존성

implementation 'org.springframework.data:spring-data-envers'

2. 부트 - Application.java

@EnableJpaAuditing
@SpringBootApplication
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

}
  • @EnableJapAuditing : auditing 기능 활성화
  • @EnableJpaAuditing(modifyOnCreate = false) : 생성 시 수정일자를 함께 등록하지 않음. (default는 true, 함께 등록함)
  • @EnableJpaAuditing(dateTimeProviderRef = "newYorkTime") : 기준시간을 변경할 수 있음.
@EnableJpaAuditing(dateTimeProviderRef = "newYorkTime")
@SpringBootApplication
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

}
@Component
@NoArgsConstructor
public class newYorkTime implements DateTimeProvider {
    @Override
    public Optional<TemporalAccessor> getNow() {
        return Optional.of(LocalDateTime.now().minusHours(14L));
    }
}
  • DateTimeProvider를 구현한 클래스를 빈으로 등록한 후, 오버라이드 한 메서드에 기준시간이 될 시간을 설정함.
  • 이후 @EnableJpaAuditing(dateTimeProviderRef = "___" 밑줄 부분에 구현한 Bean(클래스) 이름(Bean 이름이기 때문에 소문자로 시작)을 넣어주면 됨.

  • @EnableJpaAuditing(auditorAwareRef = "___” : @CreatedBy@ModifiedBy 를 사용할 때 유저 정보를 기록할 수 있음. (5-1에 추가)
    • 밑줄 부분에는 동일하게 구현한 Bean(클래스) 이름을 넣어주면 됨.(Bean 이름이기 때문에 소문자로 시작)

3. 엔티티 세팅 - Users.java

@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners(value = {AuditingEntityListener.class})
public class Users {

		@Id
    Integer id;
    String name;

    @CreatedDate
    private LocalDateTime regDt;

    @LastModifiedDate
    private LocalDateTime updateDt;

}
  • 해당 3가지 세팅을 마치고 나면 하이버네이트 JPA를 사용한 엔티티 생성, 수정 시간이 타임스탬프처럼 자동으로 찍히게 됨

4. 리스너 환경설성 - AuditingEntityListener.java

  • 기본세팅 말고 추가적인 설정을 원하면 Config로 설정하여 사용이 가능

    @Configurable
    public class AuditingEntityListener {
      
    }
    
    • AuditEntityListener는 Spring data jpa에서 구현한 EntityListener이다.
    • 5번 추가기능의 콜백 메서드들은 여기서도 세팅이 가능하다.

5. 추가 기능

  1. @CreateBy, @LastModifiedBy

    • 생성한 사람, 수정한 사람을 자동으로 저장하며, 해당 기능은 User에 대한 정보가 있어야 하기 때문에 AuditorAware 인터페이스를 구현한 클래스가 필요함

      @Component
      public class Auditor implements AuditorAware<String> {
               
          @Override
          public Optional<String> getCurrentAuditor() {
           
              return Optional.of("initial create");
          }
      }
      

      Untitled

    • Spring Security사용 중이라면 Authentication 을 이용해서 가져올 수 있음

      public class SpringSecurityAuditor implements AuditorAware<String> {	
      	@Override
          public Optional<String> getCurrentAuditor() {
           
              Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
           
              if (null == authentication || !authentication.isAuthenticated()) {
                  return Optional.empty();
              }
           
              return Optional.of(authentication.getName());
          }
      }
      
  2. @PrePersist, @PostPersist, @PreUpdate, @PostUpdate

    • @PrePersist : 엔티티가 비영속 → 영속 상태가 되기 직전 호출

    • @PostPersist : db에 insert된 후 호출

    • @PreUpdate : 데이터를 업데이트하기 전에 호출

    • @PostUpdate : 데이터를 업데이트 하고나서 호출

    • 콜백 메서드로서 리턴타입은 항상 void로 해야함

    • Users.java

      @Entity
      @Getter
      @Setter
      @Builder
      @NoArgsConstructor
      @AllArgsConstructor
      @AuditOverride(forClass = BaseEntity.class)
      public class Users extends BaseEntity {
          @Id
          Integer id;
          String name;
          String uuid;
           
          @PrePersist
          public void printPreTime() {
              UUID uuid1 = UUID.randomUUID();
              this.uuid = String.valueOf(uuid1);
              System.out.println(uuid1);
          }
           
          @PostPersist
          public void printPostTime() {
              System.out.println(this.uuid);
          }
           
      		@PreUpdate
          public void preUpdate() {
              System.out.println("업데이트 시작");
          }
           
          @PostUpdate
          public void postUpdate() {
              System.out.println("업데이트 완료");
          }
           
      }
      
      [console]
           
      //add
      Hibernate: select users0_.id as id1_0_0_, users0_.reg_dt as reg_dt2_0_0_, users0_.update_dt as update_d3_0_0_, users0_.name as name4_0_0_, users0_.uuid as uuid5_0_0_ from users users0_ where users0_.id=?
      20c0d5ed-6e62-4255-8516-da090fee2f99
      Hibernate: insert into users (reg_dt, update_dt, name, uuid, id) values (?, ?, ?, ?, ?)
      20c0d5ed-6e62-4255-8516-da090fee2f99
      add id = 6, name: Myname
           
      //update
      Hibernate: select users0_.id as id1_0_0_, users0_.reg_dt as reg_dt2_0_0_, users0_.update_dt as update_d3_0_0_, users0_.name as name4_0_0_, users0_.uuid as uuid5_0_0_ from users users0_ where users0_.id=?
      업데이트 시작
      Hibernate: update users set reg_dt=?, update_dt=?, name=?, uuid=? where id=?
      업데이트 완료
      target id = 6, name: Myname-> string
      

6. 추가 사항

1. 추상클래스 활용

  • 하나의 엔티티가 아니라 여러가지 엔티티에 동일한 이력관리를 적용하고 싶을때는 추상클래스를 활용하고 해당 클래스를 상속받아서 사용

  • BaseEntity.java

    @Getter
    @Setter
    @MappedSuperclass
    @EntityListeners(value = {AuditingEntityListener.class})
    public abstract class BaseEntity {
      
        @CreatedDate
        private LocalDateTime regDt;
      
        @LastModifiedDate
        private LocalDateTime updateDt;
      
    }
    
  • Users.java

    @Entity
    @Getter
    @Setter
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @AuditOverride(forClass = BaseEntity.class)
    public class Users extends BaseEntity {
        @Id
        Integer id;
        String name;
      
    }
    

    이렇게 사용하게 되면 기존 Users 클래스에서 이력관리를 위한 컬럼을 따로 설정해두지 않아도 되며, 테이블에는 BaseEntity의 변수들이 자동으로 컬럼으로 생성이 됨.

2. Querydsl 사용시

  • 테스트를 하던 도중 해당 기능이 계속 제대로 동작하지 않아서 생각을 해보니, Querydsl을 사용하여 Update를 하고 있었던 것.

  • Querydsl은 JPARepository를 구현하지 않는 방식으로 설계했기 때문에 해당 기능이 적용되지 않고 있었던 것.

  • UserQuerydslRepository.java

    @Repository
    @RequiredArgsConstructor
    public class UserQuerydslRepository {
      
        private final JPAQueryFactory queryFactory;
        QUsers user = new QUsers("U");
      
    		public void updateUser(Users updateUser) {
            queryFactory
                    .update(user)
                    .where(user.id.eq(updateUser.getId()))
                    .set(user.name, updateUser.getName())
                    .set(user.updateDt, LocalDateTime.now())
                    .execute();
        }
    }
    

    → 직접 이력을 관리해주는 방법

참고 레퍼런스

  • https://leo0842.github.io/spring/date-auto-create/
  • https://gist.github.com/dlxotn216/94c34a2debf848396cf82a7f21a32abe
  • https://m.blog.naver.com/rorean/221485891788

마지막 수정일시: 2023-01-30 23:40

카테고리:

업데이트:

댓글남기기