history 기능을 사용할 때 유용하다

 

history를 담을 객체를 새로 생성 (원본과 동일하게 선언)

package com.example.bookmanager.domain;

import com.example.bookmanager.domain.listener.Auditable;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.LocalDateTime;

@Data
// 상속받은 BaseEntity를 사용하기 위해서 ToString, EqualsAndHashCode 재정의
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)

@Entity
@NoArgsConstructor
// 자동으로 생성날짜, 수정날짜를 입력해주기 위해서 선언
//@EntityListeners(value = MyEntityListener.class)
// 공통 클래스 사용
//@EntityListeners(value = AuditingEntityListener.class)
// User객체에 History를 저장할 객체 생성
// BaseEntity를 상속받아 그 안에 있는 설정들을 사용할 수 있다.
public class UserHistory extends BaseEntity {
    @Id
    @GeneratedValue
//    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NonNull
    private String name;

    @NonNull
    private String email;

    // update 할 경우 값을 제외하도록 설정
//    @Column(updatable = false)
    // 자동으로 해당값을 넣어준다.
//    @CreatedDate
//    private LocalDateTime createdAt;

    // 자동으로 해당값을 넣어준다.
//    @LastModifiedDate
//    private LocalDateTime updatedAt;
}

공통으로 수정한 날짜와 생성한 날짜를 처리해줄 BaseEntity를 생성

package com.example.bookmanager.domain;

import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

// 공통으로 사용할 수정날짜, 생성날짜를 자동으로 처리해줄 Entity 선언
@EntityListeners(value = AuditingEntityListener.class)
// get, set 선언
@Data
// 해당 클래스를 상속받는 클래스에 현재 변수를 사용할 수 있도록 해주는 어노테이션
@MappedSuperclass
public class BaseEntity {
    @Column(updatable = false)
    // jpa에서 기본적으로 선언된 기능을 사용
    @CreatedDate
    private LocalDateTime createdAt;

    // jpa에서 기본적으로 선언된 기능을 사용
    @LastModifiedDate
    private LocalDateTime updatedAt;
}

 

history에 관한 jpa를 사용하기 위한 repository 생성

package com.example.bookmanager.repository;

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

public interface UserHistoryRepository extends JpaRepository<UserHistory, Long> {

}

프로젝트 메인 클래스에 @EnableJpaAuditing(Auditing을 사용하겠다는 선언) 어노테이션 선언

https://velog.io/@aidenshin/%EC%97%94%ED%8B%B0%ED%8B%B0-%EC%9E%91%EC%84%B1-JPA-Auddit-%EC%A0%81%EC%9A%A9

 

JPA 엔티티 작성 - JPA Auddit 적용

실무에서 엔티티를 생성하다보면 auddit(감사) 목적으로 거의 모든 엔티티에 들어가는 필드(컬럼)들이 있다. 일일이 작성하기 매우 귀찮은데.. Spring Data Auddit 기능을 활용하여 귀찮을 일을 줄일 수

velog.io

package com.example.bookmanager;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class BookmanagerApplication {

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

}

 

원본 DB에 데이터가 생성, 수정되었을때 처리해주기 위한 클래스 생성

package com.example.bookmanager.domain.listener;

import com.example.bookmanager.domain.User;
import com.example.bookmanager.domain.UserHistory;
import com.example.bookmanager.repository.UserHistoryRepository;
import com.example.bookmanager.support.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;

// Autowired를 사용할 경우 spring bean 등록을 진행해야 하기 때문에 Component 어노테이션을 사용한다.
//@Component
public class UserEntityListener {
//    @Autowired
//    private UserHistoryRepository userHistoryRepository;

    // 업데이트, 생성를 진행할 경우 자동으로 history에 저장되도록 설정
    @PreUpdate
    @PrePersist
    public void prePersistAndPreUpdate(Object o) {
        // UserHistoryRepository의 bean을 가져온다.
        UserHistoryRepository userHistoryRepository = BeanUtils.getBean(UserHistoryRepository.class);
        User user = (User) o;

        UserHistory userHistory = new UserHistory();
        userHistory.setId(user.getId());
        userHistory.setName(user.getName());
        userHistory.setEmail(user.getEmail());

        userHistoryRepository.save(userHistory);
    }
}

위 코드가 정상적으로 동작하기 위해서는 Repository에 bean값을 가져와야하기 때문에 그 기능을 사용하게 해 줄 클래스 생성

package com.example.bookmanager.support;

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

// Bean 클래스를 생성해주기위한 클래스
@Component
public class BeanUtils implements ApplicationContextAware {
    private 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);
    }
}

 

User 클래스에 history기능을 사용하기 위해서 @EntityListeners 어노테이션에 추가

//공통 Entity 사용
@EntityListeners(value = {AuditingEntityListener.class, UserEntityListener.class})
//@Table(name = "user", indexes = {@Index(columnList = "name")}, uniqueConstraints = {@UniqueConstraint(columnNames = {"email"})})
public class User {

 

테스트 코드

    @Autowired
    private UserHistoryRepository userHistoryRepository;
    
    @Test
    void userHistoryTest(){
        User user = new User();
        user.setEmail("martin-new@naver.com");
        user.setName("martin-new");

        userRepository.save(user);

        // 업데이트 발생
        user.setName("martin-new-new");
        userRepository.save(user);
        userHistoryRepository.findAll().forEach(System.out::println);
    }

 

처리 결과(정상적으로 history에 값이 입력되는 것을 확인 할 수 있다.)

 

'Spring > JPA' 카테고리의 다른 글

연관 관계 설정 -1  (0) 2021.07.24
연관관계, ERD  (0) 2021.07.24
Entity Listener  (0) 2021.07.18
Enum 사용 예제  (0) 2021.07.18
Entity 기본 속성  (0) 2021.07.18

+ Recent posts