Spring Boot: Entity Listener

김아무개·2023년 6월 14일
0

Spring Boot 🍃

목록 보기
38/95
post-custom-banner

Entity Listener 를 사용하여

User 테이블에 변경사항이 생길 경우

해당 히스토리를 저장하는 실습!


0. Entity Listener

@Entity Listener

JPA 엔티티에 대한 이벤트 리스너를 등록하는 어노테이션이다.

이 어노테이션을 사용하여
엔티티의 생명주기 이벤트를 수신하고
이벤트가 발생할 때 특정 동작을 수행할 수 있다.

아래 나타날 코드에서는 @EntityListener 어노테이션과,
@EntityListener 어노테이션에 할당 할
UserEntityListener 클래스를 작성하고 테스트한다.

1. User, UserHistory Entity 작성

User.java

해당 엔티티가 영속화 될 때
UserHistory 엔티티를 동작시키는 이벤트를 발생시키기 위해
@EntityListeners(value = UserEntityListener.class) 어노테이션을 붙여준다.

@ToString(callSuper = true)
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@EntityListeners(value = UserEntityListener.class) // 엔티티 리스너 부착!
@Table(name = "Users")
public class User extends BaseEntity {

    private String name;
    private String email;

}

UserHistory.java

@ToString(callSuper = true)
@Entity
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class UserHistory extends BaseEntity{

    @Enumerated(EnumType.STRING) private UserStatus status;

    private Long userId;
    private String name;
    private String email;
    @Column(name = "USER_CREATED_AT") private LocalDateTime userCreatedAt;
    @Column(name = "USER_UPDATED_AT") private LocalDateTime userUpdatedAt;

}

2. EntityListener 작성

JPA 엔티티의 생명주기에
콜백 메서드를 작성할 수 있게 해주는 어노테이션이 있다.

1 . JPA 엔티티 생명주기 에서 각각 영속화 되기 전에 반응하는
Pre 어노테이션들

@PrePersist
@PreUpdate
@PreRemove


2 . JPA 엔티티 생명주기 에서 각각 영속화 된 후에 반응하는
Post 어노테이션들

@PostPersist
@PostUpdate
@PostRemove


여기에서
Persist는 create 될 때,
Update는 update 될 때,
Remove는 delete 될 때 반응한다.


이 중에서도
실무에서 자주 사용되는 어노테이션은
@PrePersist@PreUpdate 라고 한다.


이러한 어노테이션을 이용해서

User 엔티티가 업데이트 될 때

UserHistory를 업데이트하는 UserEntityListener를 작성해본다.

public class UserEntityListener {
    private UserHistoryRepository userHistoryRepository;

    @PrePersist
    public void prePersist(Object o) {
        save((User) o, UserStatus.CREATE);
    }
    
    @PreUpdate
    public void preUpdate(Object o) {
        save((User) o, UserStatus.UPDATE);
    }
    
    @PreRemove
    public void preRemove(Object o) {
        save((User) o, UserStatus.DELETE);
    }

    private void save(User user, UserStatus status) {

        if (userHistoryRepository == null)
            userHistoryRepository = BeanUtils.getBean(UserHistoryRepository.class);

        userHistoryRepository.save(
                UserHistory.builder()
                        .status(status)
                        .userId(user.getId())
                        .name(user.getName())
                        .email(user.getEmail())
                        .userCreatedAt(user.getCreatedAt())
                        .userUpdatedAt(user.getUpdatedAt())
                        .build()
        );

    }
}

EntityListener 객체는 Bean 등록이 불가능해서 ,
UserHistoryRepository 객체를 주입받을 수 없기 때문에,

BeanUtil을 만들어서
BeanUtil을 통해 UserHistoryRepository를 가져와 사용한다.

@Component
public class BeanUtils implements ApplicationContextAware {
    static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        BeanUtils.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }
}

3. test 코드로 기능 동작 확인

test 코드

@Test
void userHistoryTest() {

    User user = User.builder()
            .name("zhyun")
            .email("gimwlgus@gmail.com")
            .build();

    // new insert
    userRepository.save(user);

    // update
    user.setEmail("zhyun@gmail.com");
    userRepository.save(user);

    // delete
    userRepository.deleteById(2001L);

    // userHistory 데이터 확인
    userHistoryRepository.findAll().forEach(System.out::println);

}

log 확인

UserHistory(super=BaseEntity(id=1, createdAt=2023-06-16T00:38:30.273039, updatedAt=2023-06-16T00:38:30.273039), status=CREATE, userId=null, name=zhyun, email=gimwlgus@gmail.com, userCreatedAt=2023-06-16T00:38:30.253169, userUpdatedAt=2023-06-16T00:38:30.253169)
UserHistory(super=BaseEntity(id=2, createdAt=2023-06-16T00:38:30.429954, updatedAt=2023-06-16T00:38:30.429954), status=UPDATE, userId=2001, name=zhyun, email=zhyun@gmail.com, userCreatedAt=2023-06-16T00:38:30.253169, userUpdatedAt=2023-06-16T00:38:30.429954)
UserHistory(super=BaseEntity(id=3, createdAt=2023-06-16T00:38:30.454453, updatedAt=2023-06-16T00:38:30.454453), status=DELETE, userId=2001, name=zhyun, email=zhyun@gmail.com, userCreatedAt=2023-06-16T00:38:30.253169, userUpdatedAt=2023-06-16T00:38:30.429954)



보고 배운 인강
오 링크가 404가 되었다..!
이럴땐 어떡해야 하지;
일단 저장..🙈;

보고 배운 인강이 판매가 중단된 것 같다.
사이트를 다 뒤져봤는데 안보임!!

여기서 사용한 코드는
강현호 강사님이 알려주신 내용을 학습한 후에 작성한 코드이다!

profile
Hello velog! 
post-custom-banner

0개의 댓글