Jin's Dev Story

[스프링 부트 쇼핑몰 프로젝트 with JPA] 5. Entity 공통 속성 공통화(Auditing) 본문

Web & Android/스프링 부트 쇼핑몰 프로젝트 with JPA

[스프링 부트 쇼핑몰 프로젝트 with JPA] 5. Entity 공통 속성 공통화(Auditing)

woojin._. 2023. 10. 15. 10:30
이 내용은 스프링 부트 쇼핑몰 프로젝트 with JPA 책을 학습한 내용입니다.

1. Auditing

엔티티에 공통으로 들어가는 멤버변수들(등록시간, 수정시간, 등록자, 수정자 등등)을 추상클래스로 만들고, 해당 추상 클래스를 상속받아 엔티티에 공통적인 기능을 수행하도록 하며 엔티티의 생성과 수정을 감시하는 기법

2. Auditing 필요성

  • 여러 엔티티에 공통된 멤버변수가 존재할 때 하나의 추상클래스로 통합하여 구현할 수 있음
  • 등록시간, 수정시간, 등록자, 수정자 등등의 엔티티 상태 변경에 대한 정보를 기록할 수 있음
  • 기록을 바탕으로 버그 문의, 업데이트 변경 대상 조회 등등 여러 상황에서 사용됨

3. AuditorAware

  • AuditorAwareImpl.java
    • 로그인한 사용자를 등록자 및 수정자로 지정하기 위해 AuditorAware 인터페이스를 구현
    • package kr.spring.config; // 현재 로그인한 사용자의 정보를 등록자와 수정자로 지정하기 위한 클래스 import org.springframework.data.domain.AuditorAware; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import java.util.Optional; public class AuditorAwareImpl implements AuditorAware<String> { @Override public Optional<String> getCurrentAuditor() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // 인증 관련 정보를 가져와 변수 생성 String userId =""; if(authentication != null) { // 유저가 존재하면 userId = authentication.getName(); // 유저 아이디 가져오기 } return Optional.of(userId); // 내용이 있으면 들고가고 없으면 빈 걸 들고감 } }

4. Auditing Config

  • AuditConfig.java
    • @EnableJpaAuditing 지정하여 Auditing 기능 활성화
    • “auditorProvider” 이름으로 AuditorAware 구현체 Bean 등록
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.domain.AuditorAware;
    import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
    
    @Configuration
    @EnableJpaAuditing //변경 발생 시 자동으로 감지할 수 있게 함
    
    public class AuditConfig {
    
      @Bean
      public AuditorAware<String> auditorProvider() {
          return new AuditorAwareImpl(); // 클래스를 생성해서 AuditorAware로 반환
      }
    
    }

5. BaseTimeEntity

  • 등록자 및 수정자 제외한 시간 관련 Auditing 기능 수행 Entity
package kr.spring.utils.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@EntityListeners(value = {AuditingEntityListener.class}) // 해당 클래스로 리스너 등록
@MappedSuperclass
@Getter
@Setter
public abstract class BaseTimeEntity { // 객체 생성 불가능하도록 abstract(추상)으로 처리

    @CreatedDate // 작성된 날 불러옴
    @Column(updatable = false) // 수정 불가(처음에 들어간 데이터로 유지됨)
    private LocalDateTime regTime;

    @LastModifiedDate // 마지막 수정일로 수정
    private LocalDateTime updateTime;

}

6. BaseEntity

  • 등록자 및 수정자, 등록 및 수정 시간을 모두 갖는 Entity
  • BaseTimeEntity 상속
package kr.spring.utils.entity;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@EntityListeners(value = {AuditingEntityListener.class}) // 해당 클래스로 리스너 등록
@MappedSuperclass
@Getter
@Setter
public abstract class BaseEntity extends BaseTimeEntity { // BaseTimeEntity를 상속받아서 한 번에 시간과 작성자를 관리

    @CreatedBy// 작성자 불러옴
    @Column(updatable = false) // 수정 불가(처음에 들어간 데이터로 유지됨)
    private String createdBy; // 작성자

    @LastModifiedBy // 마지막 수정자로 수정
    private String modifiedBy; // 수정한 사람
}

7. Member Entity Auditing

  • Member 클래스에서 BaseEntity 상속
package kr.spring.member.entity;
// 회원 엔티티
import jakarta.persistence.*;
import kr.spring.member.constant.Role;
import kr.spring.member.dto.MemberFormDto;
import kr.spring.utils.entity.BaseEntity;
import lombok.*;
import org.springframework.security.crypto.password.PasswordEncoder;

@Entity
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Member extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Column(unique = true)
    private String email;
    private String password;
    private String address;

    @Enumerated(EnumType.STRING) // 추가를 안하면 열거형은 숫자로 들어감
    private Role role;

    //사용자 만들기 -> 받아온 DTO를 entity로 변경해준다
    public static Member createMember(MemberFormDto memberFormDto, PasswordEncoder passwordEncoder) {
        //먼저 Member entity를 만들어준다.
        Member member = new Member();
        member.setName(memberFormDto.getName());  //실제 웹에서 받아올 이름이니까 dto에서 받아온다
        member.setEmail(memberFormDto.getEmail());
        member.setAddress(memberFormDto.getAddress());
        member.setRole(Role.USER);  //기본으로 다 학생으로 가입

        String password = passwordEncoder.encode(memberFormDto.getPassword());  //일단 비밀번호를 플레인 텍스트로 받아온다. 후 encode를 이용해서 암호화
        member.setPassword(password);  //암호화된 패스워드를 넣는다

        //만든 member 리턴
        return member;
    }
}
  • Item, Order, OrderItem 엔티티에는 등록시간(regTime), 수정시간(updateTime) 멤버변수가 공통
  • Spring Data Jpa에서는 Auditing 기능을 제공하여 엔티티가 저장 또는 수정될 때 자동으로 등록일, 수정일, 등록자, 수정자를 입력 가능
  • Audit의 사전적 정의는 ‘감시하다’ 즉, 엔티티의 생성과 수정을 감시