스프링 데이터 JPA-10.커스텀 리포지토리, 기본 레포지토리 커스터마이징(스프링 데이터 Common)


스프링 데이터 Common: 커스텀 리포지토리

쿼리 메소드(쿼리 생성과 쿼리 찾아쓰기)로 해결이 되지 않는 경우 직접 코딩으로 구현 가능.

  • 스프링 데이터 리포지토리 인터페이스에 기능 추가.
  • 스프링 데이터 리포지토리 기본 기능 덮어쓰기 가능.
  • 구현 방법
    • 커스텀 리포지토리 인터페이스 정의
    • 인터페이스 구현 클래스 만들기 (기본 접미어는 Impl)
    • 엔티티 리포지토리에 커스텀 리포지토리 인터페이스 추가

기능 추가하기

// 커스텀 레포지토리 (이름 상관없음) but 기본 네이밍 컨벤션을 지켜야 한다. 뒤에 Impl 붙은 클래스 만들어줘야함.
public interface PostCustomRepository {

    List<Post> findMyPost();
}
@Repository
@Transactional
public class PostCustomRepositoryImpl implements PostCustomRepository {

    @Autowired
    EntityManager entityManager;

    @Override
    public List<Post> findMyPost(){
        System.out.println("custom findMyPost");
        return entityManager.createQuery("SELECT p FROM Post AS p", Post.class)
                            .getResultList();
    }
}
// JpaRepository도 사용하면서 내가 커스텀한 PostCustomRepository 같이 사용
public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository {

}
@ExtendWith(SpringExtension.class)
@DataJpaTest
class PostRepositoryTest {

    @Autowired
    PostRepository postRepository;

    @Test
    public void crud(){
        postRepository.findMyPost(); // 정상적으로 작동(셀렉쿼리)
    }
}

기본 기능 덮어쓰기

// 커스텀 레포지토리 (이름 상관없음) but 기본 네이밍 컨벤션을 지켜야 한다. 뒤에 Impl 붙은 클래스 만들어줘야함.
public interface PostCustomRepository<T> {

    List<Post> findMyPost();

    void delete(T entity);
}
@Repository
@Transactional
public class PostCustomRepositoryImpl implements PostCustomRepository {

    @Autowired
    EntityManager entityManager;

    @Override
    public void delete(Object entity) {
        System.out.println("custom delete");
        entityManager.remove(entity);
    }
    ..
}
// JpaRepository도 사용하면서 내가 커스텀한 PostCustomRepository 같이 사용
public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRepository<Post> {
}
@ExtendWith(SpringExtension.class)
@DataJpaTest
class PostRepositoryTest {

    @Autowired
    PostRepository postRepository;

    @Test
    public void crud(){
        Post post = new Post();
        post.setTitle("hibernate");
        postRepository.save(post);

        postRepository.findMyPost();

        postRepository.delete(post); // 테스트는 어차피 롤백이라 delete 안함 (굳이 안지워도 없어지니까)
        postRepository.flush(); // 강제로 싱크 (removed 상태인 걸 싱크한다는 건 -> delete 쿼리 날린다는 것)
    }
}

접미어 설정하기

Impl 쓰기 싫은데?

@SpringBootApplication
@EnableJpaRepositories(repositoryImplementationPostfix = "Default") // Impl 대신
public class Application {

설정 후 Impl 대신 Default 붙이면 된다.

@Repository
@Transactional
public class PostCustomRepositoryDefault implements PostCustomRepository {

    @Autowired
    EntityManager entityManager;
...

스프링 데이터 Common: 기본 리포지토리 커스터마이징

모든 리포지토리에 공통적으로 추가하고 싶은 기능이 있거나 덮어쓰고 싶은 기본 기능이 있다면

  1. JpaRepository를 상속 받는 인터페이스 정의
    • @NoRepositoryBean
  2. 기본 구현체를 상속 받는 커스텀 구현체 만들기
  3. @EnableJpaRepositories에 설정
    • repositoryBaseClass
@NoRepositoryBean
public interface MyRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {

    boolean contains(T entity);
}
public class SimpleMyRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {

    private EntityManager entityManager;

    public SimpleMyRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    @Override
    public boolean contains(T entity) {
        return entityManager.contains(entity);
    }

    @Override
    public List<T> findAll() {
        System.out.println("custom findAll");
        return super.findAll();
    }
}
@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = SimpleMyRepository.class)
public class Application {
...
public interface PostRepository extends MyRepository<Post, Long> {
}
    @Test
    public void crud(){
        Post post = new Post();
        post.setTitle("hibernate");

        assertFalse(postRepository.contains(post));
        postRepository.save(post);
        assertTrue(postRepository.contains(post));

        postRepository.findAll();
    }





© 2019. by jaeuk