© 2013-2015 The original author(s).
이 문서의 복사본은 당신 자신을 위해서나, 다른 사람들에게 배포를 위해 만들어질 수 있습니다. 복사에 대해 어떤 비용을 청구하지 않아야 하며, 프린트되거나 전자적으로 배포될 때에도 Copyright 문구를 포함해야 합니다. |
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically. |
- Preface
- Reference Documentation
- Appendix
Preface
Preface
1. Project Metadata
-
버젼컨트롤 - https://github.com/spring-projects/spring-data-elasticsearch
릴리즈 리포지토리 - https://repo.spring.io/libs-release
마일스톤 repository - https://repo.spring.io/libs-milestone
스냅샷 repository - https://repo.spring.io/libs-snapshot
Version Control - https://github.com/spring-projects/spring-data-elasticsearch
Bugtracker - https://jira.spring.io/browse/DATAES
Release repository - https://repo.spring.io/libs-release
Milestone repository - https://repo.spring.io/libs-milestone
Snapshot repository - https://repo.spring.io/libs-snapshot
2. Requirements
Requires Elasticsearch 0.20.2 and above or optional dependency or not even that if you are using Embedded Node Client
스프링 데이터 레파지토리 추상화의 목표는, 다양한 영속화 저장소를 위한 데이터 액세스 레이어를 구현하는 데 있어 필요한, 상당한양의 보일러 플레이한 코드들을 줄이는 데 있습니다
The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to implement data access layers for various persistence stores.
스프링 데이터 리파지토리 문서와 당신의 모듈 Spring Data repository documentation and your module 이 챕터는 스프링 데이터 리파지토리들의 인터페이스와 핵심개념을 설명합니다. 이 챕터의 정보는 스프링데이터 공통모듈에서 나왔으며, JPA모듈을 위한 설정과 코드 샘플을 사용해봅니다. XML 네임스페이스 선언과 당신이 사용할 특별한 모듈들같은 확장되는 타입들에 적응해봅시다. (의역) Namespace reference 는 repository API를 지원하는 모든 스프링데이터모듈쪽에서 XML 설정을 다루며, Repository query keywords는 일반적으로 레파지토리추상화에 의해 지원되는 쿼리 메소드 키워드들을 다룹니다. 당신 모듈의 특별한 특징에 관한 정보를 찾는다면, 이 문서에서 그 모듈에 대한 챕터를 살펴보세요. This chapter explains the core concepts and interfaces of Spring Data repositories. The information in this chapter is pulled from the Spring Data Commons module. It uses the configuration and code samples for the Java Persistence API (JPA) module. Adapt the XML namespace declaration and the types to be extended to the equivalents of the particular module that you are using. Namespace reference covers XML configuration which is supported across all Spring Data modules supporting the repository API, Repository query keywords covers the query method keywords supported by the repository abstraction in general. For detailed information on the specific features of your module, consult the chapter on that module of this document. |
3.1. Core concepts
스프링 데이터 리파지토리 추상화에서 중심적인 인터페이스는 Repository
(아마 놀라시않으실테지만)입니다.이것은 도메인클래스와 도메인의 id 타입을 타입아규먼트로 받습니다. 이 인터페이스는 주로 마커 인터페이스로 동작하며, 작업할 타입을 가지고 있으면서, 당신이 이것을 확장할 인터페이스를 발견하게 해줍니다. CrudRepository
는 관리되는 엔티티클래스에서 복잡한 CRUD기능을 제공해줍니다.
The central interface in Spring Data repository abstraction is Repository
(probably not that much of a surprise). It takes the domain class to manage as well as the id type of the domain class as type arguments. This interface acts primarily as a marker interface to capture the types to work with and to help you to discover interfaces that extend this one. The CrudRepository
provides sophisticated CRUD functionality for the entity class that is being managed.
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity); (1)
T findOne(ID primaryKey); (2)
Iterable<T> findAll(); (3)
Long count(); (4)
void delete(T entity); (5)
boolean exists(ID primaryKey); (6)
// … more functionality omitted.
}
1 | 주어진 엔티티를 저장합니다. |
2 | 주어진 아이디로 식별된 엔티티를 반환합니다. |
3 | 모든 엔티티를 반환합니다. |
4 | 엔티티의 숫자를 반환합니다. |
5 | 주어진 엔티티를 삭제합니다. |
6 | 주어진 아이디로 엔티티가 존재하는지를 반환합니다. |
1 | Saves the given entity. |
2 | Returns the entity identified by the given id. |
3 | Returns all entities. |
4 | Returns the number of entities. |
5 | Deletes the given entity. |
6 | Indicates whether an entity with the given id exists. |
우리는 또한
JpaRepository 나 MongoRepository 같은 기술특징적인 추상화를 제공합니다. 이러한 인터페이스는 CrudRepository 를 확장하여 일반적인 기능에 좀 더 해당기술에 해당하는 기술을 사용할 수 있게 해줍니다(의역. 중요한 부분이 아니니 시간소비없이..=3=3)
We also provide persistence technology-specific abstractions like e.g.
JpaRepository or MongoRepository . Those interfaces extend CrudRepository and expose the capabilities of the underlying persistence technology in addition to the rather generic persistence technology-agnostic interfaces like e.g. CrudRepository.
|
CrudRepository
를 확장한 것 중에 PagingAndSortingRepository
는
쉽게 엔티티들에 대해 페이징을 할수있는 메소드를 제공합니다.
On top of the CrudRepository
there is a PagingAndSortingRepository
abstraction that adds additional methods to ease paginated access to entities:
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
User
의 페이지사이즈를 20으로 잡고 두번째 페이지에 접근하는 것은간단하게 이렇게 해볼수 있습니다.:
Accessing the second page of User
by a page size of 20 you could simply do something like this:
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(new PageRequest(1, 20));
public interface UserRepository extends CrudRepository<User, Long> {
Long countByLastname(String lastname);
}
public interface UserRepository extends CrudRepository<User, Long> {
Long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
3.2. Query methods
-
Repository나 그 하위 인터페이스를 상속하는 인터페이스를 상속하여, 도메인클래스와 ID 타입을 적어줍시다.
Declare an interface extending Repository or one of its subinterfaces and type it to the domain class and ID type that it will handle.
interface PersonRepository extends Repository<User, Long> { … }
-
그 인터페이스에 대해서 쿼리메소드를 선언합니다.Declare query methods on the interface.
interface PersonRepository extends Repository<User, Long> { List<Person> findByLastname(String lastname); }
-
스프링을 설정하여 이러한 인터페이스들을 위한 프록시 인스턴스를 생성하게 해줍니다. Set up Spring to create proxy instances for those interfaces. Either via 자바 설정 :
이나, XML을 통해 가능합니다.Set up Spring to create proxy instances for those interfaces. Either via JavaConfig:
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @EnableJpaRepositories class Config {}
or via XML configuration:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <jpa:repositories base-package="com.acme.repositories"/> </beans>
JPA 네임스페이스는 이 예제에서 사용되었습니다. 만약 당신이 다른 데이터 저장소를 위한 추상화 리파지토리를 사용한다면, 이것을 위해 적적한 네임스페이스 선언으로 바꿔줘야할 것입니다. 예를 들자면 몽고디비나 JPA같이 말이죠 (생략의역)
The JPA namespace is used in this example. If you are using the repository abstraction for any other store, you need to change this to the appropriate namespace declaration of your store module which should be exchanging
jpa
in favor of, for example,mongodb
.
또한, 자바설정 방법은 기본적으로 사용되는 어노테이션된 클래스를 깔끔하게 설정을 해주지않으므로 패키지를 스캔하기 위하여 다음과 같은 설정을 적어주게 됩니다. basePackage…
, @Enable…
-어노테이션.
Also, note that the JavaConfig variant doesn’t configure a package explictly as the package of the annotated class is used by default. To customize the package to scan use one of the basePackage…
attribute of the data-store specific repository @Enable…
-annotation.
-
리파지토리 인스턴스를 주입시키고 사용하세요
Get the repository instance injected and use it.
public class SomeClient { @Autowired private PersonRepository repository; public void doSomething() { List<Person> persons = repository.findByLastname("Matthews"); } }
3.3. 리파지토리 인터페이스 정의하기
3.3. Defining repository interfaces
첫번째 단계로, 당신은 도메인특정 리파지토리 인터페이스를 정의해야 합니다. 이 인터페이스는 반드시 Repository 를 상속해야 하며, 도메인 클래스와 아이디 타입을 적어줘야 합니다. 만약 당신이 CRUD메소드를 사용하기 원한다면, Repository
대신에 CrudRepository
를 사용해줍니다.
As a first step you define a domain class-specific repository interface. The interface must extend Repository and be typed to the domain class and an ID type. If you want to expose CRUD methods for that domain type, extend CrudRepository
instead of Repository
.
3.3.1. 좀 더 세밀한 리파지토리 정의 조정
3.3.1. Fine-tuning repository definition
일반적으로, 당신의 리파지토리 인터페이스는 Repository
, CrudRepository
or PagingAndSortingRepository
같은 것을 상속할 것입니다. 또 다르게는, 만약 당신이 스프링 데이터 인터페이스를 상속하기를 원하지 않는다면 당신은 당신의 리파지토리에 @RepositoryDefinition
를 붙일 수 있습니다(역주: 예제에서의 @NoRepositoryBean를 말하는 것인듯하다.). CrudRepository
를 상속하는 것은 당신의 엔티티를 다루는 메소드들의 집합을 노출시킵니다. 만약 당신이 노출되는 메소드들에 관해서 선택적으로 하고 싶다면, 단순히 CrudRepository
에서 당신이 노출시키는 부분을 복사하여 당신의 도메인 리파지토리에 붙여보셔요(^^)
Typically, your repository interface will extend Repository
, CrudRepository
or PagingAndSortingRepository
. Alternatively, if you do not want to extend Spring Data interfaces, you can also annotate your repository interface with @RepositoryDefinition
. Extending CrudRepository
exposes a complete set of methods to manipulate your entities. If you prefer to be selective about the methods being exposed, simply copy the ones you want to expose from CrudRepository
into your domain repository.
이것은 제공된 스프링데이터 리파지토리에서, 당신 자신의 추상화를 정의할 수 있게 합니다.
This allows you to define your own abstractions on top of the provided Spring Data Repositories functionality.
|
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
T save(T entity);
}
interface UserRepository extends MyBaseRepository<User, Long> {
User findByEmailAddress(EmailAddress emailAddress);
}
이 첫번째 단계에서 당신은 모든 도메인 리파지토리들을 위한 기본 작업 인터페이스를 정의하였고, findOne(…)
과 save(…)
를 노출시켰습니다. 이러한 메소드들은 리파지토리 구현 구현체에 위치하게 될 것입니다. 당신이 스프링데이터에서 선택한 저장소. 예를 들자면 JPA이면 SimpleJpaRepository
같은 것에 위치할 것입니다. 왜냐하면 이것들(역주:구현체?)은 CrudRepository
의 메소드 시그니처를 매칭시키기 때문입니다. 그러므로 UserRepository
는 사용자들을 저장하고 id로 단일유저를 찾을 수 있고, 뿐만 아니라 그들의 이메일 주소로 Users
들을 찾는 쿼리를 동작시킬 것입니다.
In this first step you defined a common base interface for all your domain repositories and exposed findOne(…)
as well as save(…)
.These methods will be routed into the base repository implementation of the store of your choice provided by Spring Data ,e.g. in the case if JPA SimpleJpaRepository
, because they are matching the method signatures in CrudRepository
. So the UserRepository
will now be able to save users, and find single ones by id, as well as triggering a query to find Users
by their email address.
@NoRepositoryBean 중간 레파지토리 인터페이스를 한번 보세요. 당신이 저 어노테이션을 붙인 모든 리파지토리는 런타임에서 인스턴스를 생성하지 않습니다.
Note, that the intermediate repository interface is annotated with
@NoRepositoryBean . Make sure you add that annotation to all repository interfaces that Spring Data should not create instances for at runtime.
|
3.4. 쿼리 메소드 정의하기
리파지토리 프록시는 메소드 이름으로 저장소에 맞는 쿼리를 만들어내는 두가지 방법이 있습니다. 하나는 메소드이름으로 직접적으로 쿼리를 만들어내는 것이고, 아니면 수동적으로 정의된 쿼리를 사용하는 것입니다. 저장소에 따라서 옵션이 더 있을 수도 있습니다. 실제 쿼리를 생성하는 것을 결정할 전략이 있을 수 있습니다. 사용가능한 옵션을 살펴볼까요?
The repository proxy has two ways to derive a store-specific query from the method name. It can derive the query from the method name directly, or by using a manually defined query. Available options depend on the actual store. However, there’s got to be a strategy that decides what actual query is created. Let’s have a look at the available options.
3.4.1. 쿼리 탐색(lookup) 전략
다음 전략에서 리파지토리 하부구조가 쿼리를 해석하는 것이 가능합니다. XML 설정의 네임스페이스에서 query-lookup-strategy
속성을 통하거나, 자바설정에서 Enable${store}Repositories어노테이션이 있는 곳에서 queryLookupStrategy
속성을 통해 전략을 설정할 수 있습니다. 몇몇 전략은 특정 데이터베이스에서 지원되지 않습니다 .
-
CREATE
는 저장소에 맞는 쿼리를 쿼리메소드이름으로 부터 만들어내는 것을 시도합니다. 일반적인 접근은 메소드이름으로부터 잘 알려진 접두어를 제거하고 나머지 부분을 파싱하는 것입니다. 쿼리생성에서 이 부분에서 좀 더 읽어보세요.Query creationCREATE
attempts to construct a store-specific query from the query method name. The general approach is to remove a given set of well-known prefixes from the method name and parse the rest of the method. Read more about query construction in Query creation. -
USE_DECLARED_QUERY
는 선언된 쿼리를 찾는 것을 시도하고, 찾을 수 없을 때는 예외를 날립니다. 쿼리는 어노테이션이나 다른 방법으로 선언된 방식에 의해 정의될 수 있습니다. 특정 데이터 저장소의 문서를 참고하셔서 그 저장소에서 사용가능한 옵션들을 찾아보세요. 만약 리파지토리 인프라스트럭처가 부트스트랩 시간에 그 메소드를 위해 정의된 쿼리를 찾을 수 없으면 이것은 실패합니다.USE_DECLARED_QUERY
tries to find a declared query and will throw an exception in case it can’t find one. The query can be defined by an annotation somewhere or declared by other means. Consult the documentation of the specific store to find available options for that store. If the repository infrastructure does not find a declared query for the method at bootstrap time, it fails. -
CREATE_IF_NOT_FOUND
(default)CREATE
와USE_DECLARED_QUERY
를 조합합니다. 이것은 처음에 정의된 쿼리를 찾아보고 발견되지 않으면, 커스텀 메소드네임 기반의 쿼리를 생성합니다. 이것은 기본 탐색전략이고, 당신이 아무것도 명시적으로 설정하지 않으면 기본 설정이 될 것입니다. 이것은 메소드이름으로 빠른 쿼리 정의를 가능케 하며, 필요에 따라 선언된 쿼리를 소개하면서 이러한 쿼리들의 커스텀 튜닝또한 가능하게 합니다.CREATE_IF_NOT_FOUND
(default) combinesCREATE
andUSE_DECLARED_QUERY
. It looks up a declared query first, and if no declared query is found, it creates a custom method name-based query. This is the default lookup strategy and thus will be used if you do not configure anything explicitly. It allows quick query definition by method names but also custom-tuning of these queries by introducing declared queries as needed.
3.4.2. 쿼리 생성
3.4.2. Query creation
쿼리 빌더 메커니즘은 스프링 데이터 리파지토리 인프라스트럭쳐로 짜여져, 리파지토리의 엔티티들에 맞는 쿼리들을 만들어내는 데 유용합니다. 이 메커니즘은 find…By
, read…By
, query…By
, count…By
, 와 get…By
같은 접두어들을 메소드에서 떼어내고 나머지부분을 파싱하기 시작합니다.
다음 소개하는 절은 Distinct
(쿼리가 생성될지 결정하는 flag를 설정)같은 더 깊은 표현을 포함하고 있습니다. 그러나 처음의 By
는 실제 크리테리아의 시작을 가리키는 구별자로 동작합니다. 기본레벨에서 당신은 엔티티의 속성을 결정할 조건을 정의할 수 있으며, 그것들을 And
와 Or
로 연결할 수 있습니다.
The query builder mechanism built into Spring Data repository infrastructure is useful for building constraining queries over entities of the repository. The mechanism strips the prefixes find…By
, read…By
, query…By
, count…By
, and get…By
from the method and starts parsing the rest of it. The introducing clause can contain further expressions such as a Distinct
to set a distinct flag on the query to be created. However, the first By
acts as delimiter to indicate the start of the actual criteria. At a very basic level you can define conditions on entity properties and concatenate them with And
and Or
.
public interface PersonRepository extends Repository<User, Long> {
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
메소드에 파싱된 실제 결과는 쿼리를 생성하는 데이터베이스에 따라 다르지만, 생각해볼만한 일반적인 것들이 있습니다.
The actual result of parsing the method depends on the persistence store for which you create the query. However, there are some general things to notice.
-
이 표현은 보통 속성을 순회하며(영어 오타인듯?) 연결될 수 있는 연산자와 함께 조합됩니다.
AND
나OR
같은 표현과 함께 속성을 조합할 수 있습니다. 당신은 또한Between
,LessThan
,GreaterThan
,Like
같은 연산자의 지원을 받을 수 있습니다. 이러한 지원되는 연산자는 데이터스토어에 따라 다를 수 있으니, 해당 레퍼런스 문서에 적절한 부분을 참고해보세요.The expressions are usually property traversals combined with operators that can be concatenated. You can combine property expressions with
AND
andOR
. You also get support for operators such asBetween
,LessThan
,GreaterThan
,Like
for the property expressions. The supported operators can vary by datastore, so consult the appropriate part of your reference documentation. -
메소드파서는 code>IgnoreCase에 대한 독립적인 flag 속성설정을 지원하며 예를 들자면
findByLastnameIgnoreCase(…)
같은 것이 되거나findByLastnameAndFirstnameAllIgnoreCase(…)
같이 모든String
인스턴스에서도 지원을 할 수 있습니다. 이 부분도 저장소에 따라 다를 수 있으니 해당 저장소 레퍼런스 문서를 참조하세요The method parser supports setting an
IgnoreCase
flag for individual properties (for example,findByLastnameIgnoreCase(…)
) or for all properties of a type that support ignoring case (usuallyString
instances, for example,findByLastnameAndFirstnameAllIgnoreCase(…)
). Whether ignoring cases is supported may vary by store, so consult the relevant sections in the reference documentation for the store-specific query method. -
당신은 정적 순서를
OrderBy
절을 추가하여 쿼리메소드의 정렬 방향을 정할 수 있습니다.Asc
나Desc
로 말이죠.. 동적 정렬을 지원하는 쿼리를 만들기 위해 특별 파라미터 핸들링를 보시기 바랍니다.You can apply static ordering by appending an
OrderBy
clause to the query method that references a property and by providing a sorting direction (Asc
orDesc
). To create a query method that supports dynamic sorting, see Special parameter handling.
3.4.3. 속성 표현
속성표현은 이전 예제에서 나타난대로, 관리되는 엔티티의 직접적인 속성을 참조할 수 있습니다. 쿼리 생성 시간에 당신은 이미 파싱된 속성이 관리되는 도메인 클래스의 일부라는 것을 확실하게 하고 가야 합니다. 그러나 당신은 중첩속성에 대한 제약을 정의할 수 있습니다. Person
이 ZipCode
와 함께 있는 Address
를 가지고 있다고 생각해봅시다. 이러한 경우 메소드 네임은
Property expressions can refer only to a direct property of the managed entity, as shown in the preceding example. At query creation time you already make sure that the parsed property is a property of the managed domain class. However, you can also define constraints by traversing nested properties. Assume a Person
has an Address
with a ZipCode
. In that case a method name of
List<Person> findByAddressZipCode(ZipCode zipCode);
이렇게 되며, x.address.zipCode
이라는 속성에 접근하게 됩니다. 이렇게 해석하는 알고리즘은 전체 부분(AddressZipCode
)을 속성으로 인터프리팅하면서 시작되어 속성에 맞는 도메인 클래스를 검사합니다. 만약 알고리즘이 성공하면, 이것은 저 속성을 사용할 것이고. 그렇지 않다면 알고리즘은 저 부분을 Camel case 부분의 오른쪽부터 왼쪽으로 그리고 꼬리부분으로 나눠보며, 맞는 속성을 찾으려 할 것입니다. 우리의 예제에서는 AddressZip
와 Code
일 것입니다. 만약 알고리즘이 앞에서 맞는 속성을 찾아내면, 거기서부터 뒷부분을 가지고서 트리다운을 만들기 시작합니다. (역주: 그 뒷부부분으로 변수를 만든다는 뜻인듯^^;) 이전에 설명한 방법대로 뒷부분을 잘라보면서 말입니다. 만약 처음 나누기가 매칭이 되지 않으면 알고리즘은 나누는 지점을 왼쪽으로 이동해보게 됩니다. (Address
, ZipCode
) 그리고 다시 시작합니다.
creates the property traversal x.address.zipCode
. The resolution algorithm starts with interpreting the entire part (AddressZipCode
) as the property and checks the domain class for a property with that name (uncapitalized). If the algorithm succeeds it uses that property. If not, the algorithm splits up the source at the camel case parts from the right side into a head and a tail and tries to find the corresponding property, in our example, AddressZip
and Code
. If the algorithm finds a property with that head it takes the tail and continue building the tree down from there, splitting the tail up in the way just described. If the first split does not match, the algorithm move the split point to the left (Address
, ZipCode
) and continues.
비록 이러한 작업이 대부분의 경우 잘 동작하지만, 잘못 동작할 경우가 있습니다. Person
가 addressZip
이라는 속성도 가지고 있다고 생각해봅시다. 이러한 알고리즘은 처음 나누면서 본질적으로 잘못된 뒷부분을 addressZip
가지게 되어 아무런 속성도 아닌(code
)것을 고르게 됩니다.
Although this should work for most cases, it is possible for the algorithm to select the wrong property. Suppose the Person
class has an addressZip
property as well. The algorithm would match in the first split round already and essentially choose the wrong property and finally fail (as the type of addressZip
probably has no code
property).
이러한 모호한 점을 해결하기 위해 당신은 _
를 당신의 메소드 이름 내에 사용하여 수동적으로 횡단지점(tracersal이라고 나와있는데 나누는 지점이라 해야 맞을듯)을 정의할 수 있습니다. 그래서 메소드 이름은 다음과 같이 끝나게 됩니다.
To resolve this ambiguity you can use _
inside your method name to manually define traversal points. So our method name would end up like so:
List<Person> findByAddress_ZipCode(ZipCode zipCode);
우리가 _를 예약된 문자어로 썼기 때문에, 우리는 강력하게 표준 자바 작명 관습을 따르기를 권합니다 . (i.e. 카멜케이스CamelCase 쓰세요^^)
As we treat underscore as a reserved character we stongly advise to follow standard Java naming conventions (i.e. not using underscores in property names but camel case instead).
3.4.4. 스페셜 파라미터 핸들링
당신의 쿼리에서 파라미터를 다루기 위해, 당신은 간단히 메소드파라미터를 예전에 봤던 예제에서 처럼 정의할 수 있습니다. 게다가 인프라스트럭쳐가 Pageable
, Sort
같은 특정 타입을 인식하여 당신의 쿼리에서 페이징과 정렬을 동적으로 하게 해줄 것입니다.
To handle parameters in your query you simply define method parameters as already seen in the examples above. Besides that the infrastructure will recognize certain specific types like Pageable
and Sort
to apply pagination and sorting to your queries dynamically.
Page<User> findByLastname(String lastname, Pageable pageable);
Slice<User> findByLastname(String lastname, Pageable pageable);
List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);
첫번째 메소드는 org.springframework.data.domain.Pageable
인스턴스를 쿼리메소드에 전달하여 정적으로 정의된 쿼리에 동적으로 페이징을 추가하게 해줍니다. Page
는 전체적인 요소의 숫자와 가능한 페이지의 개수를 알 수 있습니다. 하부구조에서 숫자조회 쿼리를 발동하여 전체적인 숫자를 계산함으로써 그것이 가능해집니다. 이것은 사용하는 저장소에 따라서 비싼 작업이 될 수도 있습니다. Slice
가 반환형으로 대신 리턴될 수도 있습니다. Slice
는 오직 다음 Slice
가 가능한지만을 알고 있으며 많은 결과 셋을 가지고 작업할 때 쓰기 충분할 것입니다.
The first method allows you to pass an org.springframework.data.domain.Pageable
instance to the query method to dynamically add paging to your statically defined query. A Page
knows about the total number of elements and pages available. It does so by the infrastructure triggering a count query to calculate the overall number. As this might be expensive depending on the store used, Slice
can be used as return instead. A Slice
only knows about whether there’s a next Slice
available which might be just sufficient when walking thought a larger result set.
정렬 옵션은 Pageable
인스턴스를 통해서도 다뤄지기도 합니다. 오직 정렬만을 필요로 한다면 org.springframework.data.domain.Sort
를 당신의 메소드에 파라미터로 전달해보세요. 당신이 보듯이, 단순히 List
를 리턴하는 것이 가능할 것입니다. 이러한 경우 실제 Page
인스턴스를 만들어내는 데 필요한 추가적인 메타데이터 생성되지 않을 것입니다 ( 여기서는 필요할지도 모르는 추가적인 카운트 쿼리가 발생되지 않는다는 것을 의미합니다 ) 대신에 단순히 쿼리를 오직 주어진 범위의 엔티티에서만으로 제한하는 것입니다.
Sorting options are handled through the Pageable
instance too. If you only need sorting, simply add an org.springframework.data.domain.Sort
parameter to your method. As you also can see, simply returning a List
is possible as well. In this case the additional metadata required to build the actual Page
instance will not be created (which in turn means that the additional count query that would have been necessary not being issued) but rather simply restricts the query to look up only the given range of entities.
당신이 쿼리에서 얼마나 많은 페이지를 얻을 수 있는지 알아보기 위해, 당신은 추가적인 count 쿼리를 동작시켜야 합니다. 기본적으로 이 쿼리는 당신이 실제적으로 동작하는 쿼리로부터 만들어집니다.
(역주 : 말이 이상한 것같은데;; 그냥 페이징 하면서 카운트 쿼리가 같이 날아간다 그런 말인 듯하다.)
To find out how many pages you get for a query entirely you have to trigger an additional count query. By default this query will be derived from the query you actually trigger.
|
3.4.5. 쿼리 결과 Limit 하기
first
나 top
를 통해서 제한될 수 있으며 바꿔 쓸수 있습니다. 선택적인 숫자값이 top/first 로 추가되어 반환될 최대 결과 크기를 명시할 수 있습니다. 만약 숫자가 무시하면 1로 가정합니다.
The results of query methods can be limited via the keywords first
or top
, which can be used interchangeably. An optional numeric value can be appended to top/first to specify the maximum result size to be returned. If the number is left out, a result size of 1 is assumed.
Top
과 First
로 결과 크기를 한계짓기 : User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
Limiting 표현은 또한 Distinct
키워드를 지원합니다. 또한 결과 셋이 하나의 인스턴스로 제한된 쿼리들을 위해 결과를 Optional
로 포장(wrapping)하는 것도 지원됩니다 .
The limiting expressions also support the Distinct
keyword. Also, for the queries limiting the result set to one instance, wrapping the result into an Optional
is supported.
만약 페이지네이션이나 슬라이싱이 제한된 쿼리 페이지네이션에 적용이 되면, (사용가능한 페이지숫자들에 적용이 되면) 이것은 제한된 결과내에서 적용됩니다.
If pagination or slicing is applied to a limiting query pagination (and the calculation of the number of pages available) then it is applied within the limited result.
Sort 파라미터를 통한 동적 정렬과 결과값을 limiting 하는 것의 조합은 쿼리메소드를 나타내게 하는 것을 허용하게 해줍니다. ( 뒷부분에 나온 for문인데 잘 이해가 안된다. for the 'K' smallest as well as for the 'K' biggest elements.)
Note that limiting the results in combination with dynamic sorting via a
Sort parameter allows to express query methods for the 'K' smallest as well as for the 'K' biggest elements.
|
3.4.6. 쿼리 결과 Streaming 하기
쿼리 메소드의 결과값은 Java8의 Stream<T>
를 이용하여 점차적으로 처리될 수 있습니다. 단순히 쿼리의 결과를 Stream
으로 포장( wrapping )하여, 데이터 스토어 특정 메소드들은 스트리밍을 하는데 사용됩니다.
The results of query methods can be processed incrementally by using a Java 8 Stream<T>
as return type. Instead of simply wrapping the query results in a Stream
data store specific methods are used to perform the streaming.
Stream<T>
로 쿼리 결과 Stream하기 :
Stream<T>
@Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();
Stream<User> readAllByFirstnameNotNull();
@Query("select u from User u")
Stream<User> streamAllPaged(Pageable pageable);
Stream 은 잠재적으로 데이터스토어특정자원을 포장(wrap)하고 사용뒤에 반드시 닫혀져야 합니다. 당신은 직접 Stream 를 close() 를 사용하여 닫아주거나 Java7의 try-with-resources블록을 사용할 수도 있습니다 .
A
Stream potentially wraps underlying data store specific resources and must therefore be closed after usage. You can either manually close the Stream using the close() method or by using a Java 7 try-with-resources block.
|
Stream<T>
와 try-with-resources 블록으로 작업해보기try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
stream.forEach(…);
}
모든 스프링 데이터 모듈이 현재
Stream<T> 를 반환타입으로 제공하는 것은 아닙니다 .
Not all Spring Data modules currently support
Stream<T> as a return type.
|
3.5. 리파지토리 인스턴스 생성하기
이 섹션에서는 당신은 리파지토리 인터페이스 정의를 위한 인스턴스들을 생성해보고 빈도 정의해봅니다.. 이것을 하는 한가지 방법은 스프링데이터모듈에 있는 Spring 네임 스페이스를 사용하는 것입니다. 비록 우리가 일반적으로 자바설정 스타일의 설정을 추천하지만, 스프링 데이터 모듈은 리파지토리 메커니즘을 지원합니다.
In this section you create instances and bean definitions for the repository interfaces defined. One way to do so is using the Spring namespace that is shipped with each Spring Data module that supports the repository mechanism although we generally recommend to use the Java-Config style configuration.
3.5.1. XML configuration
각각의 스프링 데이터 모듈은 repository 요소들을 포함하며 이 요소들은 단순하게 스프링이 스캔하는 base Package를 정의하게 해줍니다.
Each Spring Data module includes a repositories element that allows you to simply define a base package that Spring scans for you.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<repositories base-package="com.acme.repositories" />
</beans:beans>
예전의 예제에서, 스프링은 Repository
나 그 하위 인터페이스를 상속한 인터페이스들을 위해서 com.acme.repositories
를 스캔을 하기로 되어있으며, 여기서의 모든 하위패키지들들을 스캔하기로 되어있습니다. 각각의 인터페이스가 발견되면 인프라스트럭쳐는 특정기술-영속 FactoryBean
에 등록을 하여 적절한 프록시를 만들어 쿼리 메소드의 실행을 다루게 됩니다. 각각의 빈은 인터페이스로 추론된 빈 네임 아래 등록됩니다. 그래서 UserRepository
의 인터페이스는 userRepository
로 등록이 될 것입니다. base-package
속성은 와일드카드를 허용하여 당신은 스캔될 패키지로 패턴을 사용할 수도 있습니다 .
In the preceding example, Spring is instructed to scan com.acme.repositories
and all its sub-packages for interfaces extending Repository
or one of its sub-interfaces. For each interface found, the infrastructure registers the persistence technology-specific FactoryBean
to create the appropriate proxies that handle invocations of the query methods. Each bean is registered under a bean name that is derived from the interface name, so an interface of UserRepository
would be registered under userRepository
. The base-package
attribute allows wildcards, so that you can define a pattern of scanned packages.
Using filters
기본적으로 인프라스트럭쳐는 설정된 base package 밑의 각각의 특정영속기술 Repository
하위 인터페이스를 골라서, 그것을 위한 빈 인스턴스를 생성합니다. 그러나 당신은 좀더 상세한 설정을 원할 수도 있습니다. 이를 위해서 당신은 <include-filter />
나 <exclude-filter />
를 요소를 <repositories />
내부에 사용할 수도 있습니다. 이러한 문법은 스프링의 콘텍스트 네임스페이스와 정확히 동일합니다. 세부적인 사항은 스프링 레퍼런스 문서를 보시길 바랍니다. (역주: 번역문서라 스프링 공홈 변수 설정이 안됨ㅠ)
By default the infrastructure picks up every interface extending the persistence technology-specific Repository
sub-interface located under the configured base package and creates a bean instance for it. However, you might want more fine-grained control over which interfaces bean instances get created for. To do this you use <include-filter />
and <exclude-filter />
elements inside <repositories />
. The semantics are exactly equivalent to the elements in Spring’s context namespace. For details, see Spring reference documentation on these elements.
예를 들자면, 리파지토리에서 인스턴스화되는 특정 인터페이스를 제외하기 위해서 당신은 다음의 설정을 할 수도 있습니다 :
For example, to exclude certain interfaces from instantiation as repository, you could use the following configuration:
<repositories base-package="com.acme.repositories">
<context:exclude-filter type="regex" expression=".*SomeRepository" />
</repositories>
이 예제는 SomeRepository
로 끝나는 모든 요소들이 인스턴스화되지 않게 합니다.
This example excludes all interfaces ending in SomeRepository
from being instantiated.
3.5.2. 자바설정
리파지토리 인프라스트럭쳐는 자바설정에서 특정 저장소 @Enable${store}Repositories
어노테이션을 사용하여 동작합니다. 스프링콘테이너에서 자바 기반의 설정에 대한 소개를 보기 위해 , 레퍼런스 문서를 보세요.[1]
The repository infrastructure can also be triggered using a store-specific @Enable${store}Repositories
annotation on a JavaConfig class. For an introduction into Java-based configuration of the Spring container, see the reference documentation.[1]
스프링 데이터 리파지토리를 활성화시키는 간단한 설정입니다.
A sample configuration to enable Spring Data repositories looks something like this.
@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {
@Bean
public EntityManagerFactory entityManagerFactory() {
// …
}
}
예제에서는 JPA기반의 어노테이션을 사용하였지만 당신이 실제로 사용하는 저장소모듈에 따라 바꿔줄 수 있습니다.
EntityManagerFactory 빈의 정의에 똑같이 적용이 됩니다. 특정저장소 설정에 대해 다루는 섹션을 참조하세요
The sample uses the JPA-specific annotation, which you would change according to the store module you actually use. The same applies to the definition of the
EntityManagerFactory bean. Consult the sections covering the store-specific configuration.
|
3.5.3. 독립적 사용 (Standalone usage)
당신은 또한 스프링 컨테이너의 바깥에서 repository infrastructure를 사용할 수 있습니다. 예를 들자면 CDI환경도 있습니다. 당신은 여전히 클래스 패스에 스프링 라이브러리가 필요할 것이지만, 일반적으로 계획에 따라서 리파지토리들을 설정할 수 있습니다. 리파지토리 지원을 제공하는 스프링 데이터 모듈은 당신이 사용할 수 있는 특정기술영속저장소 RepositoryFactory를 가지고 있을 수 있습니다 .
You can also use the repository infrastructure outside of a Spring container, e.g. in CDI environments. You still need some Spring libraries in your classpath, but generally you can set up repositories programmatically as well. The Spring Data modules that provide repository support ship a persistence technology-specific RepositoryFactory that you can use as follows.
RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);
3.6. 스프링 데이터 리파지토리의 커스텀 구현
3.6. Custom implementations for Spring Data repositories
종종 적은 리파지토리 메소드를 위해 커스텀 구현을 제공해야할 필요가 있습니다. 스프링 데이터 리파지토리는 쉽게 커스텀 리파지토리 코드를 제공하고 , 이것을 일반적인 CRUD추상화와 쿼리 메소드 기능에 통합시키게 해줍니다.
Often it is necessary to provide a custom implementation for a few repository methods. Spring Data repositories easily allow you to provide custom repository code and integrate it with generic CRUD abstraction and query method functionality.
3.6.1. 단일 리파지토리에 커스텀 행동 추가해보기
3.6.1. Adding custom behavior to single repositories
리파지토리에 커스텀 기능을 좀 더 넣기 위해, 당신은 먼저 인터페이스를 정의하고, 그 커스텀 기능을 위한 구현체를 정의해야 합니다. repository 인터페이스를 사용하여 커스텀 인터페이스를 확장하세요.
To enrich a repository with custom functionality you first define an interface and an implementation for the custom functionality. Use the repository interface you provided to extend the custom interface.
interface UserRepositoryCustom {
public void someCustomMethod(User user);
}
class UserRepositoryImpl implements UserRepositoryCustom {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
다른 핵심리파지토리 인터페이스와 비교해봤을 때, 클래스에서 가장 중요하게 발견되는 부분은 이름의
Impl 접미어입니다. (하단 참조 )
The most important bit for the class to be found is the
Impl postfix of the name on it compared to the core repository interface (see below).
|
그 스스로의 구현은 스프링데이터에 의존하지 않으며, 정식 스프링빈이 될 수 있습니다. 그러므로 당신은 JDBCTemplate 같은 다른 빈처럼, 표준 의존성주입행동을 주입레퍼런스로써 사용할 수 있습니다. aspects에 참여시키는 것같은 일을 할 수가 있습니다.
The implementation itself does not depend on Spring Data and can be a regular Spring bean. So you can use standard dependency injection behavior to inject references to other beans like a JdbTemplate, take part in aspects, and so on.
interface UserRepository extends CrudRepository<User, Long>, UserRepositoryCustom {
// Declare query methods here
}
이제 당신의 표준 리파지토리 인터페이스를 커스텀버젼으로 확장해봅시다. CRUD와 커스텀 기능을 조합하여 클라이언트에게 사용가능하게 해봅시다.
Let your standard repository interface extend the custom one. Doing so combines the CRUD and custom functionality and makes it available to clients.
설정
만약 당신이 네임스페이스 설정을 사용한다면 리파지토리 인프라스트럭쳐는 자동으로 리파지토리를 발견한 곳에 있는 패키지에서 클래스를 스캔하여 커스텀 구현체를 찾을 것입니다. 이러한 클래스들은 네임스페이스 요소 속성 repository-impl-postfix
을 따를 필요가 있습니다. 이러한 접미어는 기본적으로 Impl
입니다.
If you use namespace configuration, the repository infrastructure tries to autodetect custom implementations by scanning for classes below the package we found a repository in. These classes need to follow the naming convention of appending the namespace element’s attribute repository-impl-postfix
to the found repository interface name. This postfix defaults to Impl
.
<repositories base-package="com.acme.repository" />
<repositories base-package="com.acme.repository" repository-impl-postfix="FooBar" />
첫번째 설정 예제에서는 com.acme.repository.UserRepositoryImpl
라는 클래스를 찾아 커스텀 리파지토리 구현체로 작동하게 할 것입니다. 반면에 두번째 예제 줄에서는 com.acme.repository.UserRepositoryFooBar
를 찾을 것입니다.
The first configuration example will try to look up a class com.acme.repository.UserRepositoryImpl
to act as custom repository implementation, whereas the second example will try to lookup com.acme.repository.UserRepositoryFooBar
.
수동 와이어링 Manual wiring
만약 당신의 커스텀 구현체가 어노테이션 기반의 설정을 사용한다면 이러한 접근은 잘 동작할 것이며, 커스텀 구현체는 다른 스프링 빈으로 잘 다뤄질 것입니다. 만약 커스텀 구현체가 특별한 와이어링을 원한다면 당신은 단순히 빈을 선언하고 앞서 선언한 컨벤션에 따라 이름지으면 됩니다. 인프라스트럭쳐는 수동으로, 새로 빈을 만드는 대신에 이름으로 정의된 빈정의를 참조할 것입니다.
The approach just shown works well if your custom implementation uses annotation-based configuration and autowiring only, as it will be treated as any other Spring bean. If your custom implementation bean needs special wiring, you simply declare the bean and name it after the conventions just described. The infrastructure will then refer to the manually defined bean definition by name instead of creating one itself.
<repositories base-package="com.acme.repository" />
<beans:bean id="userRepositoryImpl" class="…">
<!-- further configuration -->
</beans:bean>
3.6.2. 모든 리파지토리들에 커스텀 행동 추가하기 Adding custom behavior to all repositories
만약 당신이 모든 리파지토리 인터페이스에 하나의 메소드를 추가하고 싶을 때 이전의 접근들은 실현가능하지가 않았습니다.
The preceding approach is not feasible when you want to add a single method to all your repository interfaces.
-
모든 리파지토리에서 커스텀 행동을 추가하기 위해, 먼저 공유행동으로 선언할 중계인터페이스를 추가합니다.To add custom behavior to all repositories, you first add an intermediate interface to declare the shared behavior예제 20. 커스텀 공유 행동 선언하는 인터페이스An interface declaring custom shared behavior
@NoRepositoryBean public interface MyRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> { void sharedCustomMethod(ID id); }
-
이제 당신의 독립적인 리파지토리 인터페이스는
Repository
대신에 이 중계인터페이스를 상속하고, 선언된 기능을 포함할 것입니다.Now your individual repository interfaces will extend this intermediate interface instead of theRepository
interface to include the functionality declared. -
다음으로, 영속기술특징 리파지토리 빈 클래스를 상속하는 중계인터페이스의 구현체를 생성합니다. 이 클래스는 리파지토리 프록시를 위한 커스텀 base 클래스로 동작할 것입니다 .Next, create an implementation of the intermediate interface that extends the persistence technology-specific repository base class. This class will then act as a custom base class for the repository proxies.예제 21. 커스텀 리파지토리 베이스 클래스 Custom repository base class
public class MyRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> { private final EntityManager entityManager; public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager) { super(domainClass, entityManager); // Keep the EntityManager around to used from the newly introduced methods. this.entityManager = entityManager; } public void sharedCustomMethod(ID id) { // implementation goes here } }
spring의<repositories />
네임스페이스의 기본행동은base-package
아래에 있는 모든 인터페이스들에 대한 구현체를 제공하는 것입니다. 이것은 현재 상태로 남아있다면 구현체는MyRepository
의 인스턴스가 스프링에 의해 생성된다는 것을 의미합니다. 물론 이것은Repository
와 실제 엔티티를 위해 정의한 리파지토리 인터페이스간에서 중계자로 행동하기를 바라고 있는 와중에 의도한 것이 아닙니다.Repository
를 상속하는 인터페이스를 제외시키기 위해 당신은 그것을@NoRepositoryBean
로 어노테이션하거나,base-package
바깥으로 제외시켜줘야할 것입니다.The default behavior of the Spring<repositories />
namespace is to provide an implementation for all interfaces that fall under thebase-package
. This means that if left in its current state, an implementation instance ofMyRepository
will be created by Spring. This is of course not desired as it is just supposed to act as an intermediary betweenRepository
and the actual repository interfaces you want to define for each entity. To exclude an interface that extendsRepository
from being instantiated as a repository instance, you can either annotate it with@NoRepositoryBean
(as seen above) or move it outside of the configuredbase-package
. -
그러고 난 후에 커스텀 리파지토리 팩토리를 만들어 기본
RepositoryFactoryBean
를 대체하여 커스텀RepositoryFactory
을 만들어봅시다. 그러면 새로운 리파지토리 팩토리는 당신에게Repository
인터페이스를 상속하는 어떤 인터페이스의 구현체로써MyRepositoryImpl
를 제공할 것이고, 이것은SimpleJpaRepository
구현체를 대체할 것입니다.Then create a custom repository factory to replace the default
RepositoryFactoryBean
that will in turn produce a customRepositoryFactory
. The new repository factory will then provide yourMyRepositoryImpl
as the implementation of any interfaces that extend theRepository
interface, replacing theSimpleJpaRepository
implementation you just extended.예제 22. 커스텀 리파지토리 팩토리 빈 Custom repository factory beanpublic class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> { protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) { return new MyRepositoryFactory(em); } private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory { private final EntityManager em; public MyRepositoryFactory(EntityManager em) { super(em); this.em = em; } protected Object getTargetRepository(RepositoryMetadata metadata) { return new MyRepositoryImpl<T, I>((Class<T>) metadata.getDomainClass(), em); } protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { return MyRepositoryImpl.class; } } }
-
마침내, 커스텀 팩토리를 직접적으로 선언을 하거나, 스프링 네임스페이스의
factory-class
속성을 사용하거나@Enable…
어노테이션으로 repository 인프라스트럭쳐를 설정하여서, (마침내) 당신의 커스텀 팩토리 구현체를 사용하게 됩니다.Finally, either declare beans of the custom factory directly or use thefactory-class
attribute of the Spring namespace or@Enable…
annotation to instruct the repository infrastructure to use your custom factory implementation.예제 23. 커스텀 팩토리와 네임스페이스 사용하기 Using the custom factory with the namespace<repositories base-package="com.acme.repository" factory-class="com.acme.MyRepositoryFactoryBean" />
예제 24.@Enable…
어노테이션과 함께 커스텀 팩토리 사용하기@EnableJpaRepositories(factoryClass = "com.acme.MyRepositoryFactoryBean") class Config {}
3.7. 스프링 데이터 익스텐션
3.7. Spring Data extensions
3.7.1. Web support
이 섹션은 스프링 데이터 웹서포트를 위한 문서를 포함하며 스프링 데이터 웹서포트는 1.6 범위에서 스프링데이터 Commons로 구현되었습니다. 새롭게 소개된 지원이 꽤 많은 것들을 변화시켜서, 이전의 행동에 관한 문서를 우리는 레거시 웹 지원에 가지고 있습니다.
This section contains the documentation for the Spring Data web support as it is implemented as of Spring Data Commons in the 1.6 range. As it the newly introduced support changes quite a lot of things we kept the documentation of the former behavior in Legacy web support.
|
스프링 데이터 모듈은, 리파지토리 프로그래밍 모델을 지원하는 모듈이라면 다양한 방식의 웹지원을 가지고 있습니다.
웹관련 작업은 classpath의 SpringMVC JARs를 필요로 하며, 그들의 일부는 심지어 Spring Hateoas[2]를 제공하기도 합니다. 일반적으로 통합 지원은 자바설정클래스에서 @EnableSpringDataWebSupport
어노테이션을 사용함으로써 활성화됩니다.
Spring Data modules ships with a variety of web support if the module supports the repository programming model. The web related stuff requires Spring MVC JARs on the classpath, some of them even provide integration with Spring HATEOAS [2]. In general, the integration support is enabled by using the @EnableSpringDataWebSupport
annotation in your JavaConfig configuration class.
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration { }
@EnableSpringDataWebSupport
어노테이션은 우리가 뒤에 나올 새로운 컴포넌트를 등록시킵니다.
이것은 클래스패스의 Spring HATEOAS를 감지하여서, hateoas가 있다면 통합 컴포넌트로써 등록을 시킵니다.
The @EnableSpringDataWebSupport
annotation registers a few components we will discuss in a bit. It will also detect Spring HATEOAS on the classpath and register integration components for it as well if present.
SpringDataWebSupport
나 HateoasAwareSpringDataWebSupport
를 스프링 빈으로 등록합니다.
SpringDataWebSupport
or HateoasAwareSpringDataWebSupport
as Spring beans:
<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />
<!-- If you're using Spring HATEOAS as well register this one *instead* of the former -->
<bean class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration" />
기본 웹 지원
-
DomainClassConverter
는 SpringMVC 를 활성화시켜서 요청파라미터나 경로변수로부터 리파지토리 managed도메인클래스를 resolve합니다.ADomainClassConverter
to enable Spring MVC to resolve instances of repository managed domain classes from request parameters or path variables. -
HandlerMethodArgumentResolver
는 스프링 MVC로 하여금 요청파라미터로부터 Pageable 과 Sort 인스턴스를 resolve하게 해줍니다.HandlerMethodArgumentResolver
implementations to let Spring MVC resolve Pageable and Sort instances from request parameters.
도메인 클래스 콘버터 : DomainClassConverter
DomainClassConverter
는 SpringMVC 컨트롤러 시그니처에서 직접적으로 도메인 타입을 사용하게 해줍니다. 그래서 당신은 수동적으로 리파지토리를 통해 인스턴스를 찾을 필요가 없습니다.
DomainClassConverter
allows you to use domain types in your Spring MVC controller method signatures directly, so that you don’t have to manually lookup the instances via the repository:
@Controller
@RequestMapping("/users")
public class UserController {
@RequestMapping("/{id}")
public String showUserForm(@PathVariable("id") User user, Model model) {
model.addAttribute("user", user);
return "userForm";
}
}
findOne(…)
을 호출하게 합니다.
findOne(…)
on the repository instance registered for the domain type.
현재 저 리파지토리는
CrudRepository 를 구현을 하여서 전환을 위한 자격을 얻어야 합니다 .
Currently the repository has to implement
CrudRepository to be eligible to be discovered for conversion.
|
페이지화와 정렬을 위한 HandlerMethodArgumentResolvers
HandlerMethodArgumentResolvers for Pageable and Sort
위의 소스설정 일부는 또한 PageableHandlerMethodArgumentResolver
를 등록하고 SortHandlerMethodArgumentResolver
의 인스턴스를 등록합니다. 이 등록은 Pageable
과 Sort
가 유효한 컨틀롤러 메소드 아규먼트가 되게 해줍니다 .
The configuration snippet above also registers a PageableHandlerMethodArgumentResolver
as well as an instance of SortHandlerMethodArgumentResolver
. The registration enables Pageable
and Sort
being valid controller method arguments
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired UserRepository repository;
@RequestMapping
public String showUsers(Model model, Pageable pageable) {
model.addAttribute("users", repository.findAll(pageable));
return "users";
}
}
|
얻기 원하는 페이지, 0 indexed and 기본은 0. |
|
얻기 원하는 페이지 크기, 기본 20. |
|
다음의 형식으로 정렬될 형식 |
이러한 행동을 커스터마이징 하고 싶다면 @Enable
-어노테이션을 사용하는 대신에 SpringDataWebConfiguration
를 상속하거나 HATEOAS-활성화 같은 것을 하거나, pageableResolver()
나sortResolver()
메소드를 오버라이드하고 당신의 커스터마이징된 설정파일을 임포트하세요.
To customize this behavior extend either SpringDataWebConfiguration
or the HATEOAS-enabled equivalent and override the pageableResolver()
or sortResolver()
methods and import your customized configuration file instead of using the @Enable
-annotation.
이러한 경우 당신은 여러개의 테이블을 위해서, 요청으로부터 여러개의 Pageable
나 Sort
인스턴스가 resolved되기를 필요로 할지도 모릅니다. 예를 들자면 당신은 스프링의 @Qualifier
어노테이션을 사용하여 다른 것들끼리 구별을 할 수도 있습니다. 요청파라미터는 그러면 ${qualifier}_
로 prefixed됩니다. 그래서 메소드 시그니처가 다음과 같이 됩니다 :
In case you need multiple Pageable
or Sort
instances to be resolved from the request (for multiple tables, for example) you can use Spring’s @Qualifier
annotation to distinguish one from another. The request parameters then have to be prefixed with ${qualifier}_
. So for a method signature like this:
public String showUsers(Model model,
@Qualifier("foo") Pageable first,
@Qualifier("bar") Pageable second) { … }
foo_page
나 bar_page
같은 것을 만들어낼 것입니다 .
foo_page
and bar_page
etc.
Pageable
는 new PageRequest(0, 20)
와 같습니다만, Pageable
파라미터에서 @PageableDefaults
어노테이션을 통해서 커스터마이징 될 수 있습니다.
Pageable
handed into the method is equivalent to a new PageRequest(0, 20)
but can be customized using the @PageableDefaults
annotation on the Pageable
parameter.
Hypermedia support for Pageables
PagedResources
를 가지고 있어서 Page
인스턴스를, 필요한 Page
메타데이터로 풍부하게 해줄 수 있을 뿐만 아니라, 링크가 클라이언트가 쉽게 페이지를 네비게이트하게 해줍니다. Page에서 PagedResources
으로의 전환은 Spring HATEOAS ResourceAssembler
인터페이스, PagedResourcesAssembler
를 구현함으로써 이뤄집니다.
.
PagedResources
that allows enrichting the content of a Page
instance with the necessary Page
metadata as well as links to let the clients easily navigate the pages. The conversion of a Page to a PagedResources
is done by an implementation of the Spring HATEOAS ResourceAssembler
interface, the PagedResourcesAssembler
.
@Controller
class PersonController {
@Autowired PersonRepository repository;
@RequestMapping(value = "/persons", method = RequestMethod.GET)
HttpEntity<PagedResources<Person>> persons(Pageable pageable,
PagedResourcesAssembler assembler) {
Page<Person> persons = repository.findAll(pageable);
return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
}
}
위 처럼 설정을 활성화하는 것은 PagedResourcesAssembler
가 컨트롤러 메소드 아규먼트로 사용되게 해줍니다. 여기서 toResources(…)
를 호출하는 것은 다음과 같은 것을 발생하게 해줍니다 :
Enabling the configuration as shown above allows the PagedResourcesAssembler
to be used as controller method argument. Calling toResources(…)
on it will cause the following:
-
Page
의 내용이PagedResources
인스턴스의 내용(content)이 되게 해줍니다The content of thePage
will become the content of thePagedResources
instance. -
PagedResources
는, 동봉되어 채워진 정보와 함께PageMetadata
인스턴스를 얻어서Page
와 기본PageRequest
를 형성합니다. -
PagedResources
는 같이 있는 페이지의 상태에 따라prev
와next
연결을 얻습니다.. 이 링크는 메소드실행이 연결된 URI를 가리키며, 그 메소드에 추가된 페이지네이션 파라미터는PageableHandlerMethodArgumentResolver
의 설정과 매칭이 되어 링크가 나중에 resolved되게 해줍니다. -
The
PagedResources
will get aPageMetadata
instance attached populated with information form thePage
and the underlyingPageRequest
. -
The
PagedResources
getsprev
andnext
links attached depending on the page’s state. The links will point to the URI the method invoked is mapped to. The pagination parameters added to the method will match the setup of thePageableHandlerMethodArgumentResolver
to make sure the links can be resolved later on.
우리가 30명의 인원 인스턴스를 데이터베이스에 가지고 있다고 해봅시다. 당신은 이제 GET http://localhost:8080/persons
요청을 해볼 것이고, 이러한 결과를 보게 될 것입니다
Assume we have 30 Person instances in the database. You can now trigger a request GET http://localhost:8080/persons
and you’ll see something similar to this:
{ "links" : [ { "rel" : "next",
"href" : "http://localhost:8080/persons?page=1&size=20 }
],
"content" : [
… // 20 Person instances rendered here
],
"pageMetadata" : {
"size" : 20,
"totalElements" : 30,
"totalPages" : 2,
"number" : 0
}
}
당신은 정확한 URI를 만들어내고서, 기본 설정이 앞으로 들어오는 요청에 대해 파라미터를 Pageable
로 resolve하는 것을 볼 수가 있습니다. 이것이 의미하는 바는 만약 당신이 저 설정을 바꾼다면 이 연결은 자동적으로 바뀔 것입니다. (역주 : 파라미터값이 바뀌면 page metadata도 바뀐다 이말인듯?) 기본적으로 assembler는 실행될 컨트롤러 메소드를 가리킵니다. 하지만 커스텀 Link
를 제시하여 커스터마이징할 수 있고, PagedResourcesAssembler.toResource(…)
의 메소드를 오버라이딩하여 페이지네이션 링크를 만드는 데 기반이 될 수 있습니다 .
You see that the assembler produced the correct URI and also picks up the default configuration present to resolve the parameters into a Pageable
for an upcoming request. This means, if you change that configuration, the links will automatically adhere to the change. By default the assembler points to the controller method it was invoked in but that can be customized by handing in a custom Link
to be used as base to build the pagination links to overloads of the PagedResourcesAssembler.toResource(…)
method.
3.7.2. 레파지토리 생성자(popluators)
3.7.2. Repository populators
DataSource
를 생성하는데 익숙할 것입니다. 비슷한 추상화가 리파지토리 레벨에서 가능한데요. 비록 DDL로써 sql을 사용하지는 않습니다. 왜냐하면 sql은 저장소 의존적이기 때문이죠 . 그렇기 때문에 populator는 XML(스프링의 OXM추상화를 통해)과 JSON(Jackson을 통해)으로 repository에 생성할 데이터를 정의합니다.
DataSource
using SQL scripts. A similar abstraction is available on the repositories level, although it does not use SQL as the data definition language because it must be store-independent. Thus the populators support XML (through Spring’s OXM abstraction) and JSON (through Jackson) to define data with which to populate the repositories.
당신이 data.json
파일을 다음과 같이 가지고 있다고 가정해봅시다 :
Assume you have a file data.json
with the following content:
[ { "_class" : "com.acme.Person",
"firstname" : "Dave",
"lastname" : "Matthews" },
{ "_class" : "com.acme.Person",
"firstname" : "Carter",
"lastname" : "Beauford" } ]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/repository
http://www.springframework.org/schema/data/repository/spring-repository.xsd">
<repository:jackson-populator locations="classpath:data.json" />
</beans>
data.json
이 읽혀져서 Jackson ObjectMapper
를 통해 역직렬화 되게 해줍니다 .
data.json
file to
be read and deserialized via a Jackson ObjectMapper
.
JSON객체가 언마샬될 타입은 JSON문서의 _class
속성을 검사하면서 결정됩니다. 인프라스트럭쳐가 결국 적절한 리파지토리를 선택해서 막 역직렬화된 객체를 다룰 것입니다.
The type to which the JSON object will be unmarshalled to will be determined by inspecting the _class
attribute of the JSON document. The infrastructure will eventually select the appropriate repository to handle the object just deserialized.
unmarshaller-populator
요소를 사용할 수 있습니다. 당신은 SPRING OXM 공급자가 제공하는 XML marshaller 옵션 중의 하나를 사용하여서 설정을 할 수가 있습니다. 스프링 레퍼런스 가이드 문서를 살펴보세요 (역주 : 번역문서라 링크가 깨짐.. { }뭐 이런 변수가 되있다보니;; ㅎㅎ )
unmarshaller-populator
element. You configure it to use one of the XML marshaller options Spring OXM provides you with. See the Spring reference documentation for details.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/repository
http://www.springframework.org/schema/data/repository/spring-repository.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm.xsd">
<repository:unmarshaller-populator locations="classpath:data.json"
unmarshaller-ref="unmarshaller" />
<oxm:jaxb2-marshaller contextPath="com.acme" />
</beans>
3.7.3. 레거시 웹 지원
3.7.3. Legacy web support
스프링 MVC를 위한 도메인 클래스 웹 바인딩
Domain class web binding for Spring MVC
@Controller
@RequestMapping("/users")
public class UserController {
private final UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
Assert.notNull(repository, "Repository must not be null!");
this.userRepository = userRepository;
}
@RequestMapping("/{id}")
public String showUserForm(@PathVariable("id") Long id, Model model) {
// Do null check for id
User user = userRepository.findOne(id);
// Do null check for user
model.addAttribute("user", user);
return "user";
}
}
먼저 당신은 각각의 컨트롤러에 대한 각각의 의존선을 선언하여 컨트롤러나 repository에서 각자 엔티티들을 찾아야 합니다. 엔티티를 찾는 것은 또한 보일러플레이트한 작업이 될 수가 있으면 이것은 언제나 findOne(…)
을 호출합니다. 다행스럽게도 스프링은 String
값을 무작위의 값으로 전환시킬수 있는 커스텀 컴포넌트를 등록하게 해주는 방법을 제공합니다.
First you declare a repository dependency for each controller to look up the entity managed by the controller or repository respectively. Looking up the entity is boilerplate as well, as it’s always a findOne(…)
call. Fortunately Spring provides means to register custom components that allow conversion between a String
value to an arbitrary type.
PropertyEditors
PropertyEditors
가 사용되어졌었습니다. 이것과 통합하기 위해, 스프링 데이터는 DomainClassPropertyEditorRegistrar
를 제공하며 이것은 ApplicationContext
에 등록된 모든 스프링 데이터 리파지토리들을 찾고, 관리되는 도메인 클래스들을 위해서 커스텀 PropertyEditor
를 등록시킵니다.
PropertyEditors
had to be used. To integrate with that, Spring Data offers a DomainClassPropertyEditorRegistrar
, which looks up all Spring Data repositories registered in the ApplicationContext
and registers a custom PropertyEditor
for the managed domain class.
<bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="….web.bind.support.ConfigurableWebBindingInitializer">
<property name="propertyEditorRegistrars">
<bean class="org.springframework.data.repository.support.DomainClassPropertyEditorRegistrar" />
</property>
</bean>
</property>
</bean>
@Controller
@RequestMapping("/users")
public class UserController {
@RequestMapping("/{id}")
public String showUserForm(@PathVariable("id") User user, Model model) {
model.addAttribute("user", user);
return "userForm";
}
}
레퍼런스 문서
4. 엘라스틱 서치 리파지토리
4.1. 세부사항
4.1. Introduction
4.1.1. Spring Namespace
ElasticsearchServer
를 인스턴스화하기 위한 요소를 정의하게 해주는 커스텀 네임스페이스를 가지고 있습니다 .
ElasticsearchServer
.
repositories
요소를 사용하여서, 스프링 데이터 리파지토리들을 찾아보세요 리파지토리 인스턴스 생성에 나온대로 말이죠^^;
repositories
element looks up Spring Data repositories as described in Creating repository instances .
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
<elasticsearch:repositories base-package="com.acme.repositories" />
</beans>
Transport Client
나 Node Client
요소를 사용하여 Elasticsearch Server
의 인스턴스를 콘텍스트에 등록합니다.
Transport Client
or Node Client
element registers an instance of Elasticsearch Server
in the context.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
<elasticsearch:transport-client id="client" cluster-nodes="localhost:9300,someip:9300" />
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
<elasticsearch:node-client id="client" local="true"" />
</beans>
4.1.2. 어노테이션 기반 설정
4.1.2. Annotation based configuration
@Configuration
@EnableElasticsearchRepositories(basePackages = "org/springframework/data/elasticsearch/repositories")
static class Config {
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
}
}
Embedded Elasticsearch Server
를 설정하는데, 이것은 ElasticsearchTemplate
에 의해 사용됩니다. 스프링 데이터 엘라스틱 서치 리파지토리들은 @EnableElasticsearchRepositories
를 사용하여서 활성화될수 있습니다. 이 어노테이션은 본질적으로 XML 네임스페이스가 하는 것과 같은 속성의 일을 합니다. 어떠한 basepackage도 설정되지 않았다면, 이것은 하나의 설정 클래스를 사용할 것입니다. (의역있음)
Embedded Elasticsearch Server
which is used by the ElasticsearchTemplate
. Spring Data Elasticsearch Repositories are activated using the @EnableElasticsearchRepositories
annotation, which essentially carries the same attributes as the XML namespace does. If no base package is configured, it will use the one the configuration class resides in.
4.1.3. CDI를 이용하는 엘라스틱 리파지토리들
4.1.3. Elasticsearch Repositores using CDI
class ElasticsearchTemplateProducer {
@Produces
@ApplicationScoped
public ElasticsearchOperations createElasticsearchTemplate() {
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
}
}
class ProductService {
private ProductRepository repository;
public Page<Product> findAvailableBookByName(String name, Pageable pageable) {
return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
}
@Inject
public void setRepository(ProductRepository repository) {
this.repository = repository;
}
}
4.2. 쿼리 메소드들
4.2.1. 쿼리 탐색 전략
쿼리들 선언하기
@Query
어노테이션을 사용하는 것이 더 좋을 수가 있습니다. ( @Query 어노테이션 사용하기 를 보세요 ).
@Query
annotation (see Using @Query Annotation ).
4.2.2. Query 생성
public interface BookRepository extends Repository<Book, String>
{
List<Book> findByNameAndPrice(String name, Integer price);
}
{ "bool" :
{ "must" :
[
{ "field" : {"name" : "?"} },
{ "field" : {"price" : "?"} }
]
}
}
Keyword | Sample | Elasticsearch Query String |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4.2.3.
@Query 어노테이션 사용하기
Using @Query Annotation
@Query
어노테이션을 사용하여서 메소드에서 쿼리를 선언하기
@Query
annotation.
public interface BookRepository extends ElasticsearchRepository<Book, String> {
@Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
Page<Book> findByName(String name,Pageable pageable);
}
5. 엘라스틱서치 작업(Operation) 지원의 오해들
5. Miscellaneous Elasticsearch Operation Support
5.1. 필터 빌더
5.1. Filter Builder
필터 빌더는 쿼리 스피드를 향상시킵니다.
private ElasticsearchTemplate elasticsearchTemplate;
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFilter(boolFilter().must(termFilter("id", documentId)))
.build();
Page<SampleEntity> sampleEntities =
elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
5.2 큰 결과값을 위해 Scan과 Scroll 를 사용하기
5.2. Using Scan And Scroll For Big Result Set
ElasticsearchTemplate
는 scan과 scroll 메소드를 가지고서 다음과 같이 사용할 수가 있습니다.
ElasticsearchTemplate
has scan and scroll methods that can be used as below.
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withIndices("test-index")
.withTypes("test-type")
.withPageable(new PageRequest(0,1))
.build();
String scrollId = elasticsearchTemplate.scan(searchQuery,1000,false);
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
boolean hasRecords = true;
while (hasRecords){
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L , new ResultsMapper<SampleEntity>()
{
@Override
public Page<SampleEntity> mapResults(SearchResponse response) {
List<SampleEntity> chunk = new ArrayList<SampleEntity>();
for(SearchHit searchHit : response.getHits()){
if(response.getHits().getHits().length <= 0) {
return null;
}
SampleEntity user = new SampleEntity();
user.setId(searchHit.getId());
user.setMessage((String)searchHit.getSource().get("message"));
chunk.add(user);
}
return new PageImpl<SampleEntity>(chunk);
}
});
if(page != null) {
sampleEntities.addAll(page.getContent());
hasRecords = page.hasNextPage();
}
else{
hasRecords = false;
}
}
}
Appendix
부록 A : 네임 스페이스 레퍼런스
Appendix A: Namespace reference
The <repositories /> element
<repositories />
요소는 스프링 데이터 리파지토리 인프라스트럭쳐의 설정을 동작시킵니다.
가장 중요한 속성은 base-package
로 이것은 스프링 데이터 리파지토리 인터페이스[3]를 찾을 패키지를 스캔하게 해줍니다.
<repositories />
element triggers the setup of the Spring Data repository infrastructure. The most important attribute is base-package
which defines the package to scan for Spring Data repository interfaces.[3]
Name | Description |
---|---|
|
*Repository를 상속하는 리파지토리 인터페이스를 자동 감지 모드 아래 스캔하기 위해 사용됨. (실제 인터페이스는 스프링 데이터 모듈에 따라 결정된다.) 설정된 패키지의 아래 있는 모든 패키지는 스캔되며 와일드 카드 또한 가능하다. Defines the package to be used to be scanned for repository interfaces extending *Repository (actual interface is determined by specific Spring Data module) in auto detection mode. All packages below the configured package will be scanned, too. Wildcards are allowed. |
|
커스텀 리파지토리 구현체를 자동감지하기 위한 접미사를 설정한다. 설정된 접미사를 가진 클래스들은 그 후보로 고려되며 기본값은
transDefines the postfix to autodetect custom repository implementations. Classes whose names end with the configured postfix will be considered as candidates. Defaults to |
|
쿼리 검색자를 만드는데 사용되는 전략을 결정하기 위함. 쿼리 탐색 전략을 보시고 기본값은
Determines the strategy to be used to create finder queries. See Query lookup strategies for details. Defaults to |
|
외부적으로 정의된 쿼리들을 포함하는 설정파일을 찾기 위한 위치를 정의함
Defines the location to look for a Properties file containing externally defined queries.
|
|
중첩(nested) 리파지토리 인터페이스 정의를 조정할지 고려함. 기본값은
Controls whether nested repository interface definitions should be considered. Defaults to |
부록 B : Populators 네임스페이스 레퍼런스
Appendix B: Populators namespace reference
The <populator /> element
<populator />
요소는 저장소를 Spring data 리파지토리 인프라스트럭쳐[4]를 통해 채울 있게 해준다.
<populator />
element allows to populate the a data store via the Spring Data repository infrastructure.[4]
Name | Description |
---|---|
|
어디서 저장소를 채울 객체를 읽어들일 파일들을 발견할지 정함.
Where to find the files to read the objects from the repository shall be populated with.
|
부록 C : 리파지토리 쿼리 키워드들
Appendix C: Repository query keywords
지원되는 쿼리 키워드들
Supported query keywords
Logical keyword | Keyword expressions |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
부록 D : 리파지토리 쿼리 리턴 타입
Appendix D: Repository query return types
지원되는 쿼리 리턴 타입
Supported query return types
GeoResult , GeoResults , GeoPage 와 같은 지역기반 타입 은 오직 지역기반 쿼리를 지원하는 데이터저장소에서만 사용가능합니다.
Geospatial types like (
GeoResult , GeoResults , GeoPage ) are only available for data stores that support geospatial queries.
|
Return type | Description |
---|---|
|
아무런 리턴 타입 없다.
Denotes no return value.
|
Primitives |
자바 주요요소
Java primitives.
|
Wrapper types |
자바 래퍼 타입
Java wrapper types.
|
|
유니크 엔티티. 대부분 쿼리 메소드가 하나의 결과를 돌려주기를 예상합니다. 어떠한 결과도 발견되지 않은 경우
null 이 반환될 것입니다. 하나 이상의 결과가 나오게 되면 IncorrectResultSizeDataAccessException 가 나올 것입니다.
An unique entity. Expects the query method to return one result at most. In case no result is found
null is returned. More than one result will trigger an IncorrectResultSizeDataAccessException .
|
|
반복자 .
An
Iterator .
|
|
A |
|
A |
|
자바8 이나 Guava
Optional 입니다. 쿼리메소드가 대부분 하나의 결과값을 리턴하기를 기대하며 어떠한 결과도 없으면 Optional.empty() /Optional.absent() 가 반환됩니다. 하나 이상의 결과에는 IncorrectResultSizeDataAccessException 가 동작할 것입니다.
A Java 8 or Guava
Optional . Expects the query method to return one result at most. In case no result is found Optional.empty() /Optional.absent() is returned. More than one result will trigger an IncorrectResultSizeDataAccessException .
|
|
A Java 8 |
|
더 이상의 데이터가 가능한지에 대한 정보가 같이 있는 데이터의 덩어리입니다.
Pageable 를 메소드 파라미터로 필요로 합니다 .
A sized chunk of data with information whether there is more data available. Requires a
Pageable method parameter.
|
|
Slice 와 추가적인 정보가 있는 (예를 들자면 결과의 총 개수) 타입입니다. Pageable 를 메소드 파라미터로 필요로 합니다.
A
Slice with additional information, e.g. the total number of results. Requires a Pageable method parameter.
|
|
추가적인 정보(참조 위치에 대한 거리)와 함께 있는 결과 엔트리
A result entry with additional information, e.g. distance to a reference location.
|
|
추가적인 정보(참조 위치에 대한 평균 거리 )와 함께 있는
GeoResult<T> 의 리스트
A list of
GeoResult<T> with additional information, e.g. average distance to a reference location.
|
|
Page 와 GeoResult<T> ,예를 들면 참조 위치와 평균 거리
A
Page with GeoResult<T> , e.g. average distance to a reference location.
|