Back-End/JPA

스프링 데이터 JPA - 확장 기능

Meluu_ 2024. 7. 31. 14:27

✔️ 사용자 정의 리포지토리 구현


스프링 데이터 JPA 외에 

JPA 직접사용 

JDBC Template

Querydsl 사용

데이터베이스 커넥션 직접 사용 등 .. 

 

인터페이스 메서드를 직접 구현하고 싶을 때 사용

 

// 사용자 정의 인터페이스
public interface MemberRepositoryCustom {
	List<Member> findMemberCustom();
}

 

사용자 정의 인터페이스 구현 클래스

@RequiredArgsConstructor
public class memberRepositoryImpl implements MemberRepositoryCustom {

	private final EntityManager em;
    
     @Override
     public List<Member> findMemberCustom() {
         return em.createQuery("select m from Member m")
                 .getResultList();
     }
}

 

사용자 정의 인터페이스 상속

public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}

 

 

 

 

✔️ 사용자 정의 구현 클래스 


  • 규칙 : 리포지토리 인터퍼이스 이름 || 사용자 정의 인터페이스 이름 + Impl
  • 스프링 데이터 JPA가 인식해서 스프링 빈으로 등록

 

Impl 대신 다른 이름 사용시

// XML
<repositories base-package="study.datajpa.repository"
 repository-impl-postfix="Impl" />
 
 // JavaConfig 설정
 @EnableJpaRepositories(basePackages = "study.datajpa.repository", repositoryImplementationPostfix = "Impl")

 

 

여기서는
리포지토리의 이름 :  MemberRepository,
사용자 정의 인터페이스의 이름 : MemberRepositoryCustom 

 

 

 

 

 

 

 

✔️ Auditing


엔티티를 생성, 변경 시 변경한 사람과 시간을 추적하고 싶다면?

  • 등록일
  • 수정일
  • 등록자
  • 수정자

순수 JPA

@MappedSuperclass
@Getter
public class JpaBaseEntity {

    @Column(updatable = false)
    private LocalDateTime createdDate;
    private LocalDateTime updatedDate;
    
    @PrePersist
    public void prePersist() {
        LocalDateTime now = LocalDateTime.now();
        createdDate = now;
        updatedDate = now;
    }
 
    @PreUpdate
    public void preUpdate() {
        updatedDate = LocalDateTime.now();
    }
}

 

JPA 주요 이벤트 어노테이션

// em.flush() 호출될때 prePersist, preUpdate가 호출
@PrePersist // 영속화 전 콜백 메서드
@PostPersist // 영속화 후 콜백 메서드

@PreUpdate // DB에 Entity 업데이트 전 콜백 메서드
@PostUpdate // DB에 Entity 업데이트 후 콜백 메서드

 

 


 

스프링 데이터 JPA

  • @EnableJpaAuditing : 스프링 부트 설정 클래스에 적용
  • @EntityListeners(AuditingEntityListener.class) : 엔티티 적용

 

Config 클래스

@EnableJpaAuditing // Auditing 적용
@SpringBootApplication
public class DataJpaApplication {
	public static void main(String[] args) {
		SpringApplication.run(DataJpaApplication.class, args);
	}
    
    
    
    @Bean // 등록자 수정자 처리 
	public AuditorAware<String> auditorProvider() {
		return () -> Optional.of(UUID.randomUUID().toString());
	}
    // 여기서는 UUID 로 하였지만 사용자가 누군지 식별할 수 있는 값으로 하면 됨 
    
}

 

// 등록, 수정일

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseTimeEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdDate;
    
    @LastModifiedDate
    private LocalDateTime lastModifiedDate;
    
    
}

// 등록자, 수정자
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity extends BaseTimeEntity {

    @CreatedBy
    @Column(updatable = false)
    private String createdBy;
    
    @LastModifiedBy
    private String lastModifiedBy;
    }

필요한 것을 상속하여 사용하면 된다.

 

// 사용 어노테이션
@CreatedDate // Entity 생성시 자동으로 시간 저장
@LastModifiedDate // Entity 수정시 자동으로 시간 저장
@CreatedBy // 생성자의 식별값 저장
@LastModifiedBy // 수정자의 식별값 저장

 

@EntityListeners를 생략하고 싶다면

META-INF/orm.xml 에 특정 xml을 적용하면 된다. 

자세한건 강의자료 참고

 

 

 

✔️ Web 확장 - 도메인 클래스 컨버터


HTTP 파라미터로 넘어온 엔티티의 ID로 엔티티 객체를 찾아서 바인딩

 

// 조회용으로만 사용
@GetMapping("members2/{id}")
public String findMember2(@PathVariable("id") Member member) {
    return member.getUsername();
}

 

❗ 주의

트랜잭션이 없는 범위에서 엔티티를 조회하였기에 

엔티티 변경시 DB에 반영 X (더티 체킹 XXX)

 

 

 

✔️ Web 확장 - 페이징과 정렬 


 

 

@GetMapping("/members")
public Page<Member> list(Pageable pageable) {
    Page<Member> page = memberRepository.findAll(pageable);
    return page;
}

 

파라미터 : Pageable

실제 : PageRequest 객체 생성

 

 

요청 파라미터

ex) /members?page=0&size=3&sort=id, desc&sort=username, desc

page : 현제페이지, 0부터 시작

size : 한 페이지에 노출할 데이터 건수

sort : 정렬 조건 정의, sort 파라미터 추가, (asc 생략 가능)

 

 

기본값

글로벌 설정 : 스프링 부트

spring.data.web.pageable.default-page-size=20 /# 기본 페이지 사이즈/
spring.data.web.pageable.max-page-size=2000 /# 최대 페이지 사이즈/

개별 설정

@PageableDefault 어노테이션 사용

@GetMapping("/members")
public Page<MemberDto> list(@PageableDefault(size = 5) Pageable pageable) {
    return memberRepository.findAll(pageable).map(MemberDto::new);
}

 

접두사 

페이징 정보가 둘 이상이면 접두사로 구분

@Qualifier 에 접두사명 추가 "{접두사명}_xxx"

 

    @GetMapping("/memberList")
    public Page<MemberDto> list2(@Qualifier("member") @PageableDefault(size = 5) Pageable memberPageable,
                                 @Qualifier("item") @PageableDefault(size = 5) Pageable itemPageable) {
        Page<MemberDto> memberDtoPage = memberRepository.findAll(memberPageable).map(MemberDto::new);
        Page<Item> itemPage = itemRepository.findAll(itemPageable);
        return memberDtoPage;
    }

전송

postMan으로 접두사 추가하여 Get 요청

 

member 조회
item조회

MemberDtoPage 와 ItemPage가 생성

 

 

page 1부터 시작하기 <= 이는 문제가 많다. 

궁금하면 강의자료를 참조

 

 

🔖 학습내용 출처


자바 ORM 표준 JPA 프로그래밍 - 기본편 / 김영한

김영한. (2021). 자바 ORM 표준 JPA 프로그래밍. 에이콘출판사

'Back-End > JPA' 카테고리의 다른 글

스프링 데이터 JPA - 분석  (0) 2024.07.31
스프링 데이터 JPA - 페이징과 정렬, 벌크 수정  (0) 2024.07.29
스프링 데이터 JPA - 기본  (0) 2024.07.29
API 학습 내용  (0) 2024.07.15
JPA - JPQL  (0) 2024.07.12