![[실전! 스프링 데이터 JPA] 3. 확장 기능](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqiKAy%2FbtsDjY3IQu2%2FtbgwPBgXy1VGeMbbrfaakK%2Fimg.png)
인프런 김영한 강사님의 [실전! 스프링 데이터 JPA] 을 수강하고 정리한 글입니다.
실전! 스프링 데이터 JPA 강의 - 인프런
스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.
www.inflearn.com
📌 사용자 정의 리포지토리
✅ 사용자 정의 리포지토리 구현하기
Spring Data JPA가 제공하는 인터페이스를 직접 구현하려면 어떻게 해야 할까 ? (사실 그러면 구현해야 하는 기능이 너무 많다.)
JPA 직접 사용
Spring JDBC Template 사용
MyBatis 사용
DB Connection 직접 사용
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();
}
}
순수 jpa를 활용한 모습이다.
아래는 Spring Data JPA의 인터페이스에 내가 직접 만든 사용자 정의 인터페이스를 상속한 방식이다.
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}
위 처럼 대부분 사용자 정의 인터페이스의 구현 클래스 이름에는 Impl을 인터페이스 이름 뒤에 붙인다.
이 방식은 인터페이스와 구현 클래스의 이름이 비슷하여 직관적이다.
이렇게 상속하면, Spring Data JPA가 알아서 인식해서 Spring Bean으로 등록한다.
📌 Auditing
✅ 순수 JPA 를 활용한 Auditing
package study.datajpa.entity;
@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();
}
}
public class Member extends JpaBaseEntity {}
@PrePersist : 엔티티가 처음 영속화 되기 전에 실행
@PostPersist : 엔티티가 DB에 새로 저장된 직후에 실행
@PreUpdate : 엔티티가 업데이트 되기 전에 실행
@PostUpdate : DB에 업데이트 된 직후 실행
✅ Spring Data JPA를 활용한 Auditing
package jpabook.jpashop.domain;
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
@CreatedBy
@Column(updatable = false)
private String createdBy;
@LastModifiedBy
private String lastModifiedBy;
}
@CreatedDate : 등록일
@LastModifiedDate : 수정일
@CreatedBy : 등록자
@LastModifiedBy : 수정자
대신 아래처럼 등록자와 수정자를 처리하는 AuditorAware 스프링 빈을 따로 등록해줘야 한다. (등록일, 수정일은 할 필요 없다.)
@EnableJpaAuditing
@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());
}
}
📌 도메인 클래스 컨버터
✅ 도메인 클래스 컨버터 사용 전후
도메인 클래스 컨버터는 HTTP 통신 시에 파라미터로서 넘어온 엔티티의 아이디로 엔티티 객체를 알아서 찾아서 바인딩하는 것을 의미한다.
아래는 도메인 클래스 컨버터 사용 전 코드이다.
@RestController
@RequiredArgsConstructor
public class MemberController {
private final MemberRepository memberRepository;
@GetMapping("/members/{id}")
public String findMember(@PathVariable("id") Long id) {
Member member = memberRepository.findById(id).get();
return member.getUsername();
}
}
그리고 다음은 도메인 클래스 컨버터를 적용한 코드이다.
@RestController
@RequiredArgsConstructor
public class MemberController {
private final MemberRepository memberRepository;
@GetMapping("/members/{id}")
public String findMember(@PathVariable("id") Member member) {
return member.getUsername();
}
}
도메인 클래스 컨버터가 중간에 동작하여 엔티티를 조회하여 반환한 것이다.
도메인 클래스 컨버터로서 엔티티를 조회했기 때문에, 엔티티가 변경되더라도 DB에는 반영되지 않는다.
📌 페이징과 정렬
✅ 페이징과 정렬
@GetMapping("/members")
public Page<Member> list(Pageable pageable) {
Page<Member> page = memberRepository.findAll(pageable);
return page;
}
파라미터로 Pageable 객체를 받을 수 있다.
Spring Data JPA의 페이징 기능을 활용할 때 요청 파라미터의 형식은 아래와 같다.
/members?page=0&size=3&sort=id,desc&sort=username,desc
위 형식에서 page는 현재 페이지를 의미하며 0부터 시작한다.
size는 한 페이지에 노출할 데이터 건수를 의미한다.
sort는 정렬 조건을 정의한다.
만약 페이징 정보가 둘 이상일때는 접두사로 구분한다.
@Qualifier에 접두사명을 추가한다.
public String list(
@Qualifier("member") Pageable memberPageable,
@Qualifier("order") Pageable orderPageable, ...
이 방식에서 요청 파라미터의 형식은 아래와 같다.
/members?member_page=0&order_page=1
✅ DTO 페이징
엔티티를 API로서 그대로 노출하면 여러 문제가 생길 수 있다.
그렇기 때문에 엔티티를 DTO로 변환하여 반환해야 한다.
Page가 지원하는 map()을 통해 내부 데이터를 다른 것으로 변경할 수 있다.
@GetMapping("/members")
public Page<MemberDto> list(Pageable pageable) {
return memberRepository.findAll(pageable).map(MemberDto::new);
}
'Backend > JPA' 카테고리의 다른 글
[실전! Querydsl] 2. 중급 문법 (0) | 2024.01.12 |
---|---|
[실전! Querydsl] 1. 기본 문법 (1) | 2024.01.11 |
[실전! 스프링 데이터 JPA] 2. 쿼리 메소드 기능 (1) | 2024.01.10 |
[실전! 스프링 데이터 JPA] 1. 공통 인터페이스 기능 (0) | 2024.01.05 |
[자바 ORM 표준 JPA 프로그래밍 - 기본편] 11. 객체지향 쿼리 언어 2 (1) | 2024.01.05 |
개발자가 되고 싶어요.