실무에서는 주로 QueryDSL이나 SpringJdbcTemplate을 함께 사용할 때 사용함.
사용자 리포지토리가 항상 필요한 것은 아니다. 임의의 레포지토리를 만들어서 사용해도 됨.
방법
인터페이스에 작성
// interface 이름은 사용자가 임의로 지어도 무방
public interface MemberRepositoryCustom {
List<Member> findMemberCustom();
}
작성한 인터페이스를 구현하는 class 작성
class는 이름 짓는 규칙이 정해져 있음.
@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom{
// interface는 이름을 임의로 설정해도 되지만, MemberRepositoryImple의 이름은 정해져 있음.
private final EntityManager em;
@Override
public List<Member> findMemberCustom() {
return em.createQuery("select m from Member m").getResultList();
}
}
기존의 repository에 사용자가 정한 인터페이스도 상속해줌.
public interface MemberRepository extends JpaRepository<Member,Long>,MemberRepositoryCustom {
사용
@Test
public void callCustom(){
List<Member> result = memberRepository.findMemberCustom();
}
Auditing
엔티티를 생성, 변경할 때 변경한 사람과 시간을 추적하고 싶으면?
등록일, 수정일, 등록자, 수정자
순수 JPA 기능으로 구현
공통 속성 정의
@Getter
@MappedSuperclass
public class JpaBaseEntity {
@Column(updatable = false) // 업데이트 불가능
private LocalDateTime createDate;
private LocalDateTime updateDate;
@PrePersist
public void prePersist(){
LocalDateTime now = LocalDateTime.now();
createDate = now;
updateDate = now;
}
@PreUpdate
public void preUpdate(){
updateDate = LocalDateTime.now();
}
}
상속
// Member Entity
@Entity
public class Member extends JpaBaseEntity{
테스트
@Test void jpaEventBaseEntity() throws Exception{
Member member = new Member("member1");
memberRepository.save(member); // @PrePersist 작동
Thread.sleep(100);
member.setUsername("member2");
entityManager.flush();
entityManager.clear();
Member findMember = memberRepository.findById(member.getId()).get();
System.out.println("findMember = " + findMember.getCreateDate());
System.out.println("findMember = " + findMember.getUpdateDate());
}
결과
Data JPA로 구현
// @EnableJpaAuditing 어노테이션을 사용해줌.
@EnableJpaAuditing
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean // 등록, 업데이트를 한 사람이 잘 등록되는지 확인하기 위함.
public AuditorAware<String> auditorProvier(){
return () -> Optional.of(UUID.randomUUID().toString());
}
}
공통 속성Entity를 만들어준 뒤 @MaapedSuperclass 사용
순수 JPA와 다른 점은 application 클래스 위에 @EnableJpaAuditing 어노테이션과 BaseEntity에 @EntityListeners(AuditingEntityListener.class)를 사용. 속성에는 각자 역할에 맞는 어노테이션 사용해줌.
@Getter
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createDate; // 시간
@LastModifiedDate
private LocalDateTime lastModifiedDate; // 시간
@CreatedBy
@Column(updatable = false)
private String createdBy; // 만든 사람
@LastModifiedBy
private String lasteModifiedBy; // 수정한 사람
}
// 어노테이션으로 값을 받앙올 수 있음. 이것 외에도 여러 설정 값들을 정해줄 수 있음.
@GetMapping("/members")
public Page<MemberDto> list(@PageableDefault(size=5) Pageable pageable){
Page<Member> page = memberRepository.findAll(pageable);
Page<MemberDto> map = page.map(MemberDto::new);
return map;
}