Search
Duplicate
📒

[스프링 JPA] 04. 확장 기능(Auditing, 페이징과 정렬)

상태
완료
수업
JPA
주제
JPA
4 more properties
참고

사용자 정의 레포지토리

NOTE
스프링 데이터 JPA는 인터페이스만 구현하면 스프링이 구현체를 자동으로 생성해준다.
하지만 스프링 데이터 JPA가 제공하는 인터페이스를 직접 구현하려면 구현해야하는게 너무 많다!
만약 어떠한 이유로 인터페이스의 메서드를 직접 구현해야 한다면?
JPA 직접사용(EntityManager)
스프링 JDBC Template 사용
MyBatis 사용
Querydsl 사용
스프링 JPA는 이런 경우를 위해서 사용자 정의 레포지토리 기능을 제공한다!

사용자 정의 레포지토리 구현

NOTE
사용자 정의 인터페이스 명 + Impl 방식으로 사용!

1. 사용자 정의 인터페이스

public interface MemberRepositoryCustom { List<Member> findMemberCustom(); }
Java
복사

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

@RequiredArgsConstructor public class MemberRepositoryCustomImpl implements MemberRepositoryCustom { private final EntityManager em; @Override public List<Member> findMemberCustom() { return em.createQuery("select m from Member m") .getResultList(); } }
Java
복사
[ 참고]
실무에서는 주로 QueryDSL이나 SpringJdbtTemplate을 함께 사용할 때 사용자 정의 레포지토리 기능을 자주 사용한다.
항상 사용자 정의 레포지토리를 사용하기 보다는 여러 상황을 고려해서 사용하자!

Auditing

NOTE
협업할 떄 엔티티 생성, 변경한 시점과 사람의 기록을 남기는 것이 좋다!
등록일
수정일
등록자
수정자

순수 JPA 사용

NOTE
@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(); } }
Java
복사

JPA 주요 이벤트 어노테이션

@PrePersist
해당 엔티티를 저장하기 이전
@PostPersist
해당 엔티티를 저장한 이후
@PreUpdate
해당 엔티티를 업데이트 하기 이전
@PreUpdate
해당 엔티티를 업데이트 한 이후

스프링 데이터 JPA 사용

NOTE

설정

@EnableJpaAudition
스프링 부트 클래스에 적용
@EntityListeners(AuditiongEntityListener.class
엔티티에 적용

스프링 데이터 Audition 적용

@EntityListeners(AuditingEntityListener.class) @MappedSuperclass @Getter 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; }
Java
복사

주요 어노테이션

@CreateDate
데이터 생성 날짜 자동 저장 어노테이션
@LastModifiedDate
데이터 수정 날짜 자동 저장 어노테이션
@CreatedBy
데이터 생성자 자동 저장 어노테이션
@LastModifiedBy
데이터 수정자 자동 저장 어노테이션

등록자, 수정자를 처리해주는 AuditorAware 스프링 빈 등록

@Bean public AuditorAware<String> auditorProvider() { return () -> Optional.of(UUID.randomUUID().toString()); }
Java
복사
실무에서는 세션 정보나, 스프링 시큐리티 로그인 정보에서 ID를 받으면 된다.

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

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

도메인 클래스 컨버터

NOTE

적용전

@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(); } }
Java
복사
파라미터로 아이디를 받아서 해당 아이디를 가진 엔티티를 조회한다!

적용후

@GetMapping("/members2/{id}") public String findMember2(@PathVariable("id") Member member) { return member.getUserName(); }
Java
복사
도메인 클래스 컨버터가 동작해서, 해당 엔티티를 객체로 반환해준다.
[ 참고]
단순히 조회용으로만 사용해야한다!
트랜잭션이 없는 범위에서 엔티티를 조회했으므로, 엔티티를 변경해도 DB에 반영되지 않음!

Web 확장 - 페이징과 정렬

NOTE
스프링 데이터 JPA가 제공하는 페이징정렬 기능을 스프링 MVC에서 편리하게 사용가능!

페이징과 정렬 예제

NOTE
@GetMapping("/members") public Page<Member> list(Pageable pageable) { Page<Member> page = memberRepository.findAll(pageable); return page; }
Java
복사
파라미터로 Pageable을 받을 수 있다.
Pageable은 인터페이스로, 실제로는 org.springframework.data.domain.PageRequest 객체를 생성한다.
실제 반환값!

페이징과 정렬

NOTE

1. 요청 파라미터

Ex) /members?page=0&size=3&sort=id,desc&sort=username,desc
Java
복사
쿼리 파라미터로 page, size, sort를 지정해줄 수 있다!
page
현재 페이지 값
0부터 시작한다.
size
한 페이지에 노출할 데이터 건수
기본 20, 최대 2000
sort
정렬 조건을 정의한다.
기본 asc

2. 접두사

public String list( @Qualifier("member") Pageable memberPageable, @Qualifier("order") Pageable orderPageable, ... )
Java
복사
페이징 정보가 둘 이상이면, 접두사로 구분한다.
@Qualifier에 접두사명 추가 “{접두사명}_xxx”
ex) /members?member_page=0&order_page=1

3. Page 내용을 DTO로 변환하기

@GetMapping("/members") public Page<MemberDto> list(Pageable pageable){ Page<Member> page = memberRepository.findAll(pageable); Page<MemberDto> map = page.map(member -> new MemberDto(member.getId(), member.getUserName(), null)); return map; }
Java
복사
엔티티를 API로 노출하면 모든 정보가 노출되어 다양한 문제가 발생한다.
그래서 꼭 엔티티를 DTO로 변환해서 반환해야 한다!
Pagemap()을 지원해서 내부 데이터를 다른 것으로 변경할 수 있다.