Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

Entity Listener : 2 본문

JPA

Entity Listener : 2

Seung__ 2021. 6. 16. 23:00

히스토리 데이터의 경우 db의 특정 데이터가 수정이 되면 해당 값의 복사본은 다른 테이블에 복사해 두는 경우가 있음.

 

이전에 만든 user에 대한 정보는 중요한 정보로, 데이터의 수정이 이뤄졌을 때 수정된 내역의 히스토리가 필요하닫.

 

1.UserHistory class


User의 수정 History 정보를 담을 클래스를 작성하자.

package com.jpa.bookmanager.domain;
import lombok.*;


import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.time.LocalDateTime;

@Entity
@NoArgsConstructor
@Data
public class UserHistory {

    @Id
    @GeneratedValue
    private long id;

    private Long userId;

    private String name;

    private String email;

    private LocalDateTime createdAt;

    private LocalDateTime updatedAt;

}

2. UserHistoryRepository


package com.jpa.bookmanager.repository;

import com.jpa.bookmanager.domain.UserHistory;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserHistoryRepository extends JpaRepository<UserHistory, Long> {
}

 

3. UserHistoryListener class


package com.jpa.bookmanager.domain;

import com.jpa.bookmanager.repository.UserHistoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.persistence.PreUpdate;

@Component
public class UserEntityListener {

    @Autowired
    private UserHistoryRepository userHistoryRepository;

    @PreUpdate
    public void preUpdate(Object o){
        User user = (User) o;
        UserHistory userHistory = new UserHistory();
        userHistory.setUserId(user.getId());
        userHistory.setName(user.getName());
        userHistory.setEmail(user.getEmail());

        userHistoryRepository.save(userHistory);


    }
}

 

@Autowired를 사용하려면 class가 @Componant지정하여 Bean을 주입받아야 한다.

 

 

 

4. User class에 EnttityListeners수정


UserEntiryListener를 사용하기 위해  value에 추가해 주자.

해당 Listener가 User에 수정이 있을 경우 감시를 하다가 PreUpdate관련된 메서드를 실행할 예정.

@EntityListeners(value = {MyEntityListener.class, UserEntityListener.class})

5. Test


  @Test
    void userHistoryTest(){
        User user  = new User();
        user.setEmail("hyun19@navernaver.com");
        user.setName("hyun19");

        userRepository.save(user);

        user.setName("hyun20_new");
        userRepository.save(user);

        userHistoryRepository.findAll().forEach(System.out::println);
    }

6. 결과


Caused by: java.lang.NullPointerException
at com.jpa.bookmanager.domain.UserEntityListener.preUpdate(UserEntityListener.java:23)

짠! preUpdate에서 NullPointException 이 발생했다. 해당 method에서 nullpointexception이 발생할 수 있는 경우는
userHistoryRepository가 Null인 경우이다.

 

여기서 중요한 사실, Entity Listener는 Spring bean을 주입받지 못한다.

따라서 정상적으로 작동을 하지 않아 userHistoryRepository가 Null이 된 것.

 

 

 

7. BeanUtils class생성


 

따라서 Spring Bean을 가져올 수 있는 특별한 class가 별도로 필요하다.

 

package com.jpa.bookmanager.support;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component //bean으로 등록
public class BeanUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        BeanUtils.applicationContext = applicationContext;
        //applicationContext를 주입받음
    }

    public static <T> T getBean(Class<T> clazz){
        return applicationContext.getBean(clazz);
        //clazz에 있는 빈을 리턴
    }
}

 

* Bean : 스프링에서 관리하는 객체

* Application context : spring bean을 생성하고 관리

 

즉 BeanUtils를 통해 application context를 주입을 받고,

application context에서 내가 원하는 class의 bean을 가져올 수 있다.

 

8. UserEntityListener 수정


  1) @Autowired로 UserHistporyRepository를 연결하지 않고

  2) preUpdate() 실행 시 UserHistoryRepository에 BeanUtils를 통해서 bean을 주입해준다.

package com.jpa.bookmanager.domain;

import com.jpa.bookmanager.repository.UserHistoryRepository;
import com.jpa.bookmanager.support.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.persistence.PreUpdate;

//@Component //bean으로 등록
public class UserEntityListener {
    

   // @Autowired
    //private UserHistoryRepository userHistoryRepository;

    @PreUpdate
    public void preUpdate(Object o){
        UserHistoryRepository userHistoryRepository = BeanUtils.getBean(UserHistoryRepository.class);

        User user = (User) o;
        
        UserHistory userHistory = new UserHistory();
        userHistory.setUserId(user.getId());
        userHistory.setName(user.getName());
        userHistory.setEmail(user.getEmail());

        userHistoryRepository.save(userHistory);


    }
}

 

9.결과2


Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        user
        (created_at, email, gender, name, updated_at, id) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.created_at as created_2_1_0_,
        user0_.email as email3_1_0_,
        user0_.gender as gender4_1_0_,
        user0_.name as name5_1_0_,
        user0_.updated_at as updated_6_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        user_history
        (created_at, email, name, updated_at, user_id, id) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    update
        user 
    set
        created_at=?,
        email=?,
        gender=?,
        name=?,
        updated_at=? 
    where
        id=?
Hibernate: 
    select
        userhistor0_.id as id1_2_,
        userhistor0_.created_at as created_2_2_,
        userhistor0_.email as email3_2_,
        userhistor0_.name as name4_2_,
        userhistor0_.updated_at as updated_5_2_,
        userhistor0_.user_id as user_id6_2_ 
    from
        user_history userhistor0_
UserHistory(id=7, userId=6, name=hyun20_new, 
            email=hyun19@navernaver.com, createdAt=null, updatedAt=null)

 

10. 최종

1) 생성/수정시간 입력을 위해 UserHistory가 Autitable을 구현하도록 한다.

@EntityListeners(value = MyEntityListener.class)
public class UserHistory implements Auditable{

2) UserEntityListener가 prePersist, preUpdate에서 동작하도록 한다.

    @PrePersist
    @PreUpdate
    public void prePersistpreUpdate(Object o){

 

3) 결과

Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        user_history
        (created_at, email, name, updated_at, user_id, id) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        user
        (created_at, email, gender, name, updated_at, id) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.created_at as created_2_1_0_,
        user0_.email as email3_1_0_,
        user0_.gender as gender4_1_0_,
        user0_.name as name5_1_0_,
        user0_.updated_at as updated_6_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        user_history
        (created_at, email, name, updated_at, user_id, id) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    update
        user 
    set
        created_at=?,
        email=?,
        gender=?,
        name=?,
        updated_at=? 
    where
        id=?
Hibernate: 
    select
        userhistor0_.id as id1_2_,
        userhistor0_.created_at as created_2_2_,
        userhistor0_.email as email3_2_,
        userhistor0_.name as name4_2_,
        userhistor0_.updated_at as updated_5_2_,
        userhistor0_.user_id as user_id6_2_ 
    from
        user_history userhistor0_
UserHistory(id=6, userId=null, name=hyun19, email=hyun19@navernaver.com, 
            createdAt=2021-06-16T22:55:06.430384, updatedAt=2021-06-16T22:55:06.430384)
UserHistory(id=8, userId=7, name=hyun20_new, email=hyun19@navernaver.com, 
            createdAt=2021-06-16T22:55:06.576311, updatedAt=2021-06-16T22:55:06.576311)

user의 정보가 생성/수정 될 때 userHistory에 그 정보가 기록되는것을 확인이 가능하다.

'JPA' 카테고리의 다른 글

Entity Listener : 4(실제 사용하는 방법)  (0) 2021.06.16
Entity Listener : 3(@AuditingEntityListener)  (0) 2021.06.16
Entity Listener - 1  (0) 2021.06.15
@Entity 속성 2  (0) 2021.06.15
@Entity 기본 속성 - 1  (0) 2021.06.15
Comments