-
Spring Boot: Entity ListenerSpring Boot 🍃 2023. 12. 5. 00:01
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가 되었다..! 이럴땐 어떡해야 하지; 일단 저장..🙈;보고 배운 인강이 판매가 중단된 것 같다. 사이트를 다 뒤져봤는데 안보임!!
여기서 사용한 코드는 강현호 강사님이 알려주신 내용을 학습한 후에 작성한 코드이다!
'Spring Boot 🍃' 카테고리의 다른 글
Spring boot: JPA 연관관계 살펴보기 - 1:N (0) 2023.12.06 Spring boot: JPA 연관관계 살펴보기 - 1:1 (0) 2023.12.05 Spring boot: H2 DB 인텔리제이에서 확인하기 (0) 2023.12.05 Spring boot : sql dummy data 만들기 (0) 2023.12.05 Spring boot: RestTemplate - Naver 지역 검색 api 연동해보기 (0) 2023.12.05