Spring Data Elasticsearch
BioMed Central Development Team版本3.1.5.RELEASE,2019年2月13日
©2013-2019原始作者。
本文档的副本可以供您自己使用,也可以分发给其他人,但前提是您不对此类副本收取任何费用,并且还应确保每份副本均包含本版权声明(无论是印刷版本还是电子版本)。 |
---|
Spring Data Elasticsearch项目将Spring的核心概念应用于使用Elasticsearch Search
Engine的解决方案的开发中。我们将“模板”作为用于存储,查询,排序和构面文档的高级抽象。您会注意到与Spring框架中的Spring数据solr和mongodb支持相似。
版本控制-https://github.com/spring-projects/spring-data-elasticsearch
Bugtracker- https: //jira.spring.io/browse/DATAES
发布存储库-https: //repo.spring.io/libs-release
里程碑资料库-https: //repo.spring.io/libs-milestone
快照存储库-https: //repo.spring.io/libs-snapshot
需要Elasticsearch 0.20.2及更高版本或可选依赖项,即使您使用的是嵌入式节点客户端,也不需要
Spring数据存储库抽象的目标是显着减少实现各种持久性存储的数据访问层所需的样板代码量。
Spring Data Repository文档和您的模块 本章介绍了Spring Data存储库的核心概念和接口。本章中的信息来自Spring Data Commons模块。它使用Java Persistence API(JPA)模块的配置和代码示例。您应该使XML名称空间声明和类型适应于所使用的特定模块的等效项。“ 命名空间参考 ”介绍了XML配置,所有支持存储库API的Spring Data模块都支持该配置。“ 存储库查询关键字 ”通常涵盖存储库抽象支持的查询方法关键字。有关模块的特定功能的详细信息,请参阅本文档中有关该模块的章节。 |
---|
Spring
Data存储库抽象中的中央接口是Repository。它需要域类以及域类的ID类型作为类型参数来进行管理。该接口主要用作标记接口,以捕获要使用的类型并帮助您发现扩展该接口的接口。该CrudRepository规定对于正在管理的实体类复杂的CRUD功能。
例子1. CrudRepository界面
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity);
Optional<T> findById(ID primaryKey);
Iterable<T> findAll();
long count();
void delete(T entity);
boolean existsById(ID primaryKey);
// … more functionality omitted.
}
保存给定的实体。 | |
---|---|
返回由给定ID标识的实体。 | |
返回所有实体。 | |
返回实体数。 | |
删除给定的实体。 | |
指示是否存在具有给定ID的实体。 | |
我们还提供了特定于持久性技术的抽象,例如JpaRepository或MongoRepository。这些接口CrudRepository除了扩展了与持久性技术无关的通用接口(例如)之外,还扩展并公开了基础持久性技术的功能CrudRepository。 |
在之上CrudRepository,有一个PagingAndSortingRepository抽象,它添加了其他方法来简化对实体的分页访问:
例子2. PagingAndSortingRepository界面
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
要访问第二个页面(User页面大小为20),您可以执行以下操作:
PagingAndSortingRepository
Page
除了查询方法外,还可以使用计数和删除查询的查询派生。以下列表显示派生计数查询的接口定义:
*例子3.派生计数查询*
interface UserRepository extends CrudRepository<User, Long> {
long countByLastname(String lastname);
}
以下列表显示了派生的删除查询的接口定义:
*例子4.派生的删除查询*
interface UserRepository extends CrudRepository<User, Long> {
long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
标准CRUD功能存储库通常在基础数据存储上进行查询。使用Spring
Data,声明这些查询将分为四个步骤:
interface PersonRepository extends Repository
{ … }
在接口上声明查询方法。
interface PersonRepository extends Repository
List
}
设置Spring以使用JavaConfig或XML
configuration为这些接口创建代理实例。
import
org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories
class Config {}
要使用XML配置,请定义类似于以下内容的bean:
<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赞成,例如mongodb。
+另外,请注意,JavaConfig变量不会显式配置程序包,因为默认情况下使用带注释的类的程序包。要自定义要扫描的包,请使用basePackage…特定于数据存储库的@Enable${store}Repositories-annotation 的属性之一。
注入存储库实例并使用它,如以下示例所示:
class SomeClient {
private final PersonRepository repository;
SomeClient(PersonRepository repository) {
this.repository = repository;
}
void doSomething() {
List<Person> persons = repository.findByLastname("Matthews");
}
}
以下各节详细说明了每个步骤:
定义存储库接口
定义查询方法
创建存储库实例
Spring数据存储库的定制实现
首先,定义特定于域类的存储库接口。该接口必须扩展Repository并键入域类和ID类型。如果要公开该域类型的CRUD方法,请扩展CrudRepository而不是Repository。
通常情况下,你的资料库接口扩展Repository,CrudRepository或PagingAndSortingRepository。另外,如果您不想扩展Spring
Data接口,也可以使用注释您的存储库接口@RepositoryDefinition。扩展提供CrudRepository了一套完整的方法来操纵您的实体。如果您希望对公开的方法保持选择性,请将要公开的方法复制CrudRepository到域存储库中。
这样做可以让您在提供的Spring Data Repositories功能之上定义自己的抽象。 |
---|
下面的示例示出了如何以选择性地露出CRUD方法(findById和save,在这种情况下):
*例子5.有选择地公开CRUD方法*
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends Repository<T,
ID> {
Optional<T> findById(ID id);
<S extends T> S save(S entity);
}
interface UserRepository extends MyBaseRepository<User, Long> {
User findByEmailAddress(EmailAddress emailAddress);
}
在前面的示例中,您为所有域存储库定义了一个通用的基本接口,并公开findById(…)了以及save(…)这些接口。这些方法被路由到Spring
Data提供的所选存储的基本存储库实现中(例如,如果您使用JPA,实现是SimpleJpaRepository),因为它们与中的方法签名相匹配CrudRepository。因此,他们UserRepository现在可以保存用户,按ID查找单个用户,并触发查询以Users按电子邮件地址查找。
中间存储库接口用注释@NoRepositoryBean。确保将注释添加到所有存储库接口,Spring Data不应在运行时为其创建实例。 |
---|
从Spring Data 2.0开始,返回单个聚合实例的存储库CRUD方法使用Java
8 Optional表示可能没有值。除此之外,Spring
Data支持在查询方法上返回以下包装器类型:
com.google.common.base.Optional
scala.Option
io.vavr.control.Option
javaslang.control.Option (不推荐使用,因为不推荐使用Javaslang)
另外,查询方法可以选择根本不使用包装器类型。然后通过返回来表示查询结果的缺失null。保证返回集合,集合替代项,包装器和流的存储库方法从不返回null,而是相应的空表示。有关详细信息,请参见“ 存储库查询返回类型 ”。
可空性注释
您可以使用Spring
Framework的nullability批注来表达存储库方法的nullability约束。它们提供了一种对工具友好的方法,并null在运行时进行了选择加入检查,如下所示:
@NonNullApi:在包级别用于声明参数和返回值的默认行为是不接受或产生null值。
@NonNull:用于不得包含的参数或返回值null (适用时,不需要参数和返回值@NonNullApi)。
@Nullable:用于可以为的参数或返回值null。
Spring注释使用JSR
305注释(休眠但分布广泛的JSR)进行元注释。JSR
305元注释使工具供应商(如IDEA,Eclipse和Kotlin)以通用方式提供了空安全支持,而无需对Spring注释进行硬编码支持。为了对查询方法的可空性约束进行运行时检查,您需要使用Spring的@NonNullApiin 来在包级别激活非可空性package-info.java,如以下示例所示:
*例子6.在声明非空性 package-info.java*
@org.springframework.lang.NonNullApi
package com.acme;
一旦设置了非null默认值,就可以在运行时验证存储库查询方法的调用是否具有可空性约束。如果查询执行结果违反了定义的约束,则会引发异常。当方法返回null但被声明为不可为空时(在存储库所在的包中定义了注释的默认值),将发生这种情况。如果您想再次选择接受可为空的结果,请选择性地@Nullable在各个方法上使用。使用本节开头提到的结果包装器类型可以按预期继续工作:将空结果转换为表示缺席的值。
下面的示例显示了刚才描述的许多技术:
*例子7.使用不同的可空性约束*
package com.acme;
import org.springframework.lang.Nullable;
interface UserRepository extends Repository<User, Long> {
User getByEmailAddress(EmailAddress emailAddress);
@Nullable
User findByEmailAddress(@Nullable EmailAddress emailAdress);
Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress);
}
存储库位于我们已为其定义非空行为的包(或子包)中。 | |
---|---|
EmptyResultDataAccessException当执行查询不产生结果时抛出。传递给方法IllegalArgumentException时抛出。emailAddressnull | |
null当执行的查询不产生结果时返回。也接受null作为的值emailAddress。 | |
Optional.empty()当执行的查询不产生结果时返回。传递给方法IllegalArgumentException时抛出。emailAddressnull |
基于Kotlin的存储库中的可空性
Kotlin定义了语言中包含的可空性约束。Kotlin代码编译为字节码,字节码不通过方法签名来表达可空性约束,而是通过内置的元数据来表达。确保kotlin-reflect在您的项目中包含JAR,以对Kotlin的可空性约束进行自省。Spring
Data存储库使用语言机制来定义这些约束以应用相同的运行时检查,如下所示:
*例子8.在Kotlin仓库上使用可空性约束*
interface UserRepository : Repository<User, String> {
fun findByUsername(username: String): User
fun findByFirstname(firstname: String?): User?
}
该方法将参数和结果都定义为不可为空(Kotlin默认值)。Kotlin编译器拒绝传递null给该方法的方法调用。如果查询执行产生空结果,EmptyResultDataAccessException则抛出。 | |
---|---|
该方法接受null的firstname参数,并返回null,如果查询执行不产生结果。 |
在您的应用程序中使用唯一的Spring
Data模块使事情变得简单,因为已定义范围中的所有存储库接口均已绑定到Spring
Data模块。有时,应用程序需要使用多个Spring
Data模块。在这种情况下,存储库定义必须区分持久性技术。当它在类路径上检测到多个存储库工厂时,Spring
Data进入严格的存储库配置模式。严格的配置使用存储库或域类上的详细信息来决定有关存储库定义的Spring
Data模块绑定:
如果存储库定义扩展了特定于模块的存储库,则它是特定Spring
Data模块的有效候选者。
如果域类使用模块特定的类型注释进行注释,则它是特定Spring
Data模块的有效候选者。Spring
Data模块可以接受第三方注释(例如JPA的注释@Entity),也可以提供自己的注释(例如@DocumentSpring
Data MongoDB和Spring Data Elasticsearch 的注释)。
以下示例显示使用特定于模块的接口(在这种情况下为JPA)的存储库:
*示例9.使用特定于模块的接口的存储库定义*
interface MyRepository extends JpaRepository<User, Long> { }
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends
JpaRepository<T, ID> {
…
}
interface UserRepository extends MyBaseRepository<User, Long> {
…
}
MyRepository并UserRepository扩展JpaRepository其类型层次结构。它们是Spring Data
JPA模块的有效候选者。
以下示例显示了使用通用接口的存储库:
*例子10.使用通用接口的存储库定义*
interface AmbiguousRepository extends Repository<User, Long> {
…
}
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends
CrudRepository<T, ID> {
…
}
interface AmbiguousUserRepository extends MyBaseRepository<User, Long> {
…
}
AmbiguousRepository和AmbiguousUserRepository仅延伸Repository,并CrudRepository在他们的类型层次。尽管在使用唯一的Spring
Data模块时这很好,但是多个模块无法区分这些存储库应绑定到哪个特定的Spring Data。
以下示例显示了使用带注释的域类的存储库:
*例子11.使用带有注释的域类的存储库定义*
interface PersonRepository extends Repository<Person, Long> {
…
}
@Entity
class Person {
…
}
interface UserRepository extends Repository<User, Long> {
…
}
@Document
class User {
…
}
PersonRepositoryreferences Person,它使用JPA @Entity注释进行了注释,因此该存储库显然属于Spring
Data JPA。UserRepository引用User,使用Spring Data
MongoDB的@Document注释进行注释。
以下不良示例显示了使用带有混合批注的域类的存储库:
*例子12.使用带有混合注释的域类的存储库定义*
interface JpaPersonRepository extends Repository<Person, Long> {
…
}
interface MongoDBPersonRepository extends Repository<Person, Long> {
…
}
@Entity
@Document
class Person {
…
}
此示例显示了同时使用JPA和Spring Data
MongoDB批注的域类。它定义了两个存储库JpaPersonRepository和MongoDBPersonRepository。一个用于JPA,另一个用于MongoDB。Spring
Data不再能够区分存储库,这导致不确定的行为。
存储库类型详细信息和可区分的域类注释用于严格的存储库配置,以标识特定Spring
Data模块的存储库候选者。在同一个域类型上使用多个特定于持久性技术的注释是可能的,并且可以跨多种持久性技术重用域类型。但是,Spring
Data无法再确定用于绑定存储库的唯一模块。
区分存储库的最后一种方法是确定存储库基础包的范围。基本软件包定义了扫描存储库接口定义的起点,这意味着将存储库定义放在适当的软件包中。默认情况下,注释驱动的配置使用配置类的包。基于XML的配置中的基本软件包是必需的。
以下示例显示了基础包的注释驱动配置:
*例子13.基础包的注释驱动配置*
@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")
interface Configuration { }
存储库代理有两种从方法名称派生特定于商店的查询的方式:
通过直接从方法名称派生查询。
通过使用手动定义的查询。
可用选项取决于实际商店。但是,必须有一种策略可以决定要创建的实际查询。下一节将介绍可用的选项。
以下策略可用于存储库基础结构来解决查询。使用XML配置,您可以通过query-lookup-strategy属性在名称空间中配置策略。对于Java配置,可以使用注释的queryLookupStrategy属性Enable${store}Repositories。某些数据存储可能不支持某些策略。
CREATE尝试从查询方法名称构造特定于商店的查询。通用方法是从方法名称中删除一组给定的众所周知的前缀,然后解析该方法的其余部分。您可以在“ 查询创建 ”中阅读有关查询构造的更多信息。
USE_DECLARED_QUERY尝试查找已声明的查询,如果找不到则抛出异常。该查询可以通过某处的注释定义,也可以通过其他方式声明。请查阅特定商店的文档以找到该商店的可用选项。如果存储库基础结构在引导时找不到该方法的声明查询,则它将失败。
CREATE_IF_NOT_FOUND(默认)组合CREATE和USE_DECLARED_QUERY。它首先查找一个声明的查询,如果找不到声明的查询,它将创建一个基于名称的自定义方法查询。这是默认的查找策略,因此,如果未显式配置任何内容,则使用该策略。它允许通过方法名称快速定义查询,也可以通过根据需要引入已声明的查询来自定义调整这些查询。
内置在Spring
Data存储库基础结构中的查询构建器机制对于在存储库实体上构建约束查询很有用。该机制条前缀find…By,read…By,query…By,count…By,和get…By从所述方法和开始解析它的其余部分。Introduction子句可以包含其他表达式,例如a,Distinct以在要创建的查询上设置不同的标志。但是,第一个By充当分隔符以指示实际标准的开始。在最基本的级别上,您可以定义实体属性的条件,并将其与And和串联Or。下面的示例演示如何创建许多查询:
*例子14.从方法名查询创建*
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);
}
解析该方法的实际结果取决于您为其创建查询的持久性存储。但是,需要注意一些一般事项:
表达式通常是属性遍历,并带有可串联的运算符。您可以使用AND和组合属性表达式OR。您还可以得到这样的运营商为支撑Between,LessThan,GreaterThan,和Like该属性的表达式。支持的运算符可能因数据存储而异,因此请参考参考文档的相应部分。
方法解析器支持IgnoreCase为单个属性(例如findByLastnameIgnoreCase(…))或支持忽略大小写的类型的所有属性(通常是String实例,例如findByLastnameAndFirstnameAllIgnoreCase(…))设置标志。是否支持忽略大小写可能因商店而异,因此请参考参考文档中有关商店特定查询方法的相关部分。
您可以通过将OrderBy子句附加到引用属性的查询方法并提供排序方向(Asc或Desc)来应用静态排序。要创建支持动态排序的查询方法,请参阅“ 特殊参数处理 ”。
如上例所示,属性表达式只能引用被管实体的直接属性。在查询创建时,您已经确保已解析的属性是托管域类的属性。但是,您也可以通过遍历嵌套属性来定义约束。考虑以下方法签名:
List
假设Person的Address带有ZipCode。在这种情况下,该方法将创建属性遍历x.address.zipCode。解析算法首先将整个部分(AddressZipCode)解释为属性,然后检查域类中具有该名称的属性(未大写)。如果算法成功,它将使用该属性。如果不是,该算法将驼峰案例部分的源从右侧分为头和尾,并尝试找到相应的属性-在我们的示例中为AddressZip和Code。如果该算法找到了具有该头部的属性,则它将采用该头部,并继续从那里开始构建树,以刚才描述的方式将尾部向上拆分。如果第一个分割不匹配,则算法会将分割点移到左侧(Address,ZipCode)并继续。
尽管这在大多数情况下应该可行,但是算法可能会选择错误的属性。假设Person该类也具有一个addressZip属性。该算法将在第一轮拆分中已经匹配,选择错误的属性,然后失败(因为类型addressZip可能没有code属性)。
要解决这种歧义,您可以_在方法名称内部使用手动定义遍历点。因此,我们的方法名称如下:
List
因为我们将下划线字符视为保留字符,所以我们强烈建议您遵循以下标准Java命名约定(即,在属性名称中不使用下划线,而使用驼峰大小写)。
要处理查询中的参数,请定义方法参数,如前面的示例所示。除此之外,基础架构还可以识别某些特定类型(例如Pageable和)Sort,以将分页和排序动态应用于您的查询。以下示例演示了这些功能:
*例子15. 在查询方法中使用Pageable,Slice和Sort*
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实例传递给查询方法,以将分页动态添加到静态定义的查询中。A Page知道可用元素和页面的总数。它是通过基础结构触发计数查询来计算总数来实现的。由于这可能很昂贵(取决于所使用的商店),因此您可以改为返回Slice。一个Slice只知道无论下一个Slice是可用的,通过一个较大的结果集行走时,这可能是足够的。
排序选项也通过Pageable实例处理。如果只需要排序,则将一个org.springframework.data.domain.Sort参数添加到您的方法中。如您所见,List也可以返回a 。在这种情况下,Page不会创建构建实际实例所需的其他元数据(这反过来,这意味着不会发出本来必要的其他计数查询)。而是,它将查询限制为仅查找给定范围的实体。
要找出整个查询可获得多少页,您必须触发其他计数查询。默认情况下,此查询派生自您实际触发的查询。 |
---|
可以通过使用firstor top关键字来限制查询方法的结果,这些关键字可以互换使用。可以将可选的数值附加到top或first指定要返回的最大结果大小。如果省略数字,则假定结果大小为1。以下示例显示了如何限制查询大小:
*例子16.用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);
限制表达式也支持Distinct关键字。此外,对于将结果集限制为一个实例的查询,Optional支持使用关键字将结果包装到其中。
如果将分页或切片应用于限制查询分页(以及对可用页面数的计算),则会在限制结果内应用分页或切片。
通过使用Sort参数来限制结果与动态排序的组合,可以让您表达针对最小的“ K”元素和针对“ K”的最大元素的查询方法。 |
---|
通过使用Java
8 Stream
*例子17.用Java 8流式查询的结果 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潜在封装底层数据存储专用资源,因此必须在使用之后被关闭。您可以Stream使用close()方法或使用Java 7 try-with-resources块来手动关闭,如以下示例所示: |
---|
*例子18. Stream<T>在try-with-resources块中处理结果*
try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
stream.forEach(…);
}
当前,并非所有的Spring Data模块都支持Stream |
---|
可以使用Spring的异步方法执行功能来异步运行存储库查询。这意味着该方法在调用时立即返回,而实际查询执行发生在已提交给Spring的任务中TaskExecutor。异步查询执行与反应式查询执行不同,因此不应混为一谈。有关响应式支持的更多详细信息,请参阅商店特定的文档。以下示例显示了许多异步查询:
@Async
Future<User> findByFirstname(String firstname);
@Async
CompletableFuture<User> findOneByFirstname(String firstname);
@Async
ListenableFuture<User> findOneByLastname(String lastname);
使用java.util.concurrent.Future作为返回类型。 | |
---|---|
使用Java 8 java.util.concurrent.CompletableFuture作为返回类型。 | |
使用a org.springframework.util.concurrent.ListenableFuture作为返回类型。 |
在本部分中,将为已定义的存储库接口创建实例和Bean定义。一种方法是使用支持存储库机制的每个Spring
Data模块随附的Spring名称空间,尽管我们通常建议使用Java配置。
每个Spring
Data模块都包含一个repositories元素,可让您定义Spring会为您扫描的基本软件包,如以下示例所示:
*例19.通过XML启用Spring Data存储库*
<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>
在前面的示例中,指示Spring扫描com.acme.repositories及其所有子包以查找扩展的接口Repository或其中一个子接口。对于找到的每个接口,基础结构都会注册特定FactoryBean于持久性技术的内容,以创建处理查询方法调用的适当代理。每个Bean都以从接口名称派生的Bean名称注册,因此的接口UserRepository将在之下注册userRepository。该base-package属性允许使用通配符,以便您可以定义扫描程序包的模式。
使用过滤器
默认情况下,基础架构会拾取扩展Repository位于配置的基本程序包下的特定于持久性技术的子接口的每个接口,并为其创建一个bean实例。但是,您可能希望更精细地控制哪些接口具有为其创建的Bean实例。为此,请在元素内部使用
例如,要将某些接口从实例中排除为存储库Bean,可以使用以下配置:
*例子20.使用exclude-filter元素*
<repositories base-package="com.acme.repositories">
<context:exclude-filter type="regex" expression=".\*SomeRepository" />
repositories>
前面的示例排除了所有以结尾的接口SomeRepository。
还可以通过@Enable${store}Repositories在JavaConfig类上使用商店特定的注释来触发存储库基础结构。有关Spring容器基于Java的配置的简介,请参见Spring参考文档中的JavaConfig。
启用Spring数据存储库的示例配置类似于以下内容:
*例子21.基于样本注释的存储库配置*
@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {
@Bean
EntityManagerFactory entityManagerFactory() {
// …
}
}
前面的示例使用特定于JPA的注释,您将根据实际使用的商店模块对其进行更改。EntityManagerFactoryBean 的定义也是如此。请参阅涵盖商店特定配置的部分。 |
---|
您还可以在Spring容器之外使用存储库基础结构,例如在CDI环境中。您的类路径中仍然需要一些Spring库,但是,通常,您也可以通过编程方式来设置存储库。提供存储库支持的Spring
Data模块附带了特定RepositoryFactory于持久性技术的代码,您可以按以下方式使用它:
*例子22.独立使用仓库工厂*
RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);
本节介绍存储库定制以及片段如何形成复合存储库。
当查询方法需要不同的行为或无法通过查询派生实现时,则有必要提供自定义实现。Spring
Data存储库使您可以提供自定义存储库代码,并将其与通用CRUD抽象和查询方法功能集成。
要使用自定义功能丰富存储库,必须首先定义片段接口和自定义功能的实现,如以下示例所示:
*示例23.定制存储库功能的接口*
interface CustomizedUserRepository {
void someCustomMethod(User user);
}
然后,可以让您的存储库接口另外从片段接口扩展,如以下示例所示:
*例子24.定制仓库功能的实现*
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
类名中与片段接口相对应的最重要部分是Impl后缀。 |
---|
实现本身不依赖于Spring Data,可以是常规的Spring
bean。因此,您可以使用标准的依赖项注入行为来注入对其他bean(例如JdbcTemplate)的引用,参与各个方面,等等。
您可以让您的存储库接口扩展片段接口,如以下示例所示:
*示例25.对您的存储库界面的更改*
interface UserRepository extends CrudRepository<User, Long>,
CustomizedUserRepository {
// Declare query methods here
}
用存储库接口扩展片段接口,将CRUD和自定义功能结合在一起,并使它可用于客户端。
Spring
Data存储库是通过使用构成存储库组成的片段来实现的。片段是基础存储库,功能方面(例如QueryDsl)以及自定义接口及其实现。每次向存储库接口添加接口时,都通过添加片段来增强组合。每个Spring
Data模块都提供了基础存储库和存储库方面的实现。
以下示例显示了自定义接口及其实现:
*例子26.片段及其实现*
interface HumanRepository {
void someHumanMethod(User user);
}
class HumanRepositoryImpl implements HumanRepository {
public void someHumanMethod(User user) {
// Your custom implementation
}
}
interface ContactRepository {
void someContactMethod(User user);
User anotherContactMethod(User user);
}
class ContactRepositoryImpl implements ContactRepository {
public void someContactMethod(User user) {
// Your custom implementation
}
public User anotherContactMethod(User user) {
// Your custom implementation
}
}
以下示例显示了扩展的自定义存储库的界面CrudRepository:
*例子27.对您的存储库界面的更改*
interface UserRepository extends CrudRepository<User, Long>, HumanRepository,
ContactRepository {
// Declare query methods here
}
存储库可能由多个自定义实现组成,这些自定义实现按其声明顺序导入。自定义实现比基础实现和存储库方面的优先级更高。通过此顺序,您可以覆盖基础存储库和方面方法,并在两个片段贡献相同方法签名的情况下解决歧义。存储库片段不限于在单个存储库界面中使用。多个存储库可以使用片段接口,使您可以跨不同的存储库重用自定义项。
以下示例显示了存储库片段及其实现:
*例子28.片段覆盖 save(…)*
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
```java
以下示例显示了使用上述存储库片段的存储库:
```java
*例子29.定制的仓库接口*
interface UserRepository extends CrudRepository<User, Long>,
CustomizedSave<User> {
}
interface PersonRepository extends CrudRepository<Person, Long>,
CustomizedSave<Person> {
}
组态
如果使用名称空间配置,则存储库基础结构会尝试通过扫描发现存储库的包下方的类来自动检测自定义实现片段。这些类需要遵循将命名空间元素的repository-impl-postfix属性附加到片段接口名称的命名约定。此后缀默认为Impl。以下示例显示了使用默认后缀的存储库和为后缀设置自定义值的存储库:
*例子30.配置例子*
<repositories base-package="com.acme.repository" />
<repositories base-package="com.acme.repository"
repository-impl-postfix="MyPostfix" />
上一个示例中的第一个配置尝试查找一个称为com.acme.repository.CustomizedUserRepositoryImpl自定义存储库实现的类。第二个示例尝试查找com.acme.repository.CustomizedUserRepositoryMyPostfix。
解决歧义
如果在不同的包中找到具有匹配类名的多个实现,Spring
Data将使用Bean名称来标识要使用的那个。
给定CustomizedUserRepository前面显示的以下两个自定义实现,将使用第一个实现。它的bean名称是customizedUserRepositoryImpl,与片段接口(CustomizedUserRepository)和后缀的名称匹配Impl。
*例子31.歧义实现的解决*
package com.acme.impl.one;
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
// Your custom implementation
}
package com.acme.impl.two;
@Component("specialCustomImpl")
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
// Your custom implementation
}
如果您使用注释UserRepository接口@Component(“specialCustom”),则Bean名称plus Impl将与在中为存储库实现定义的名称匹配com.acme.impl.two,并且将使用它代替第一个。
手动接线
如果您的自定义实现仅使用基于注释的配置和自动装配,则上述显示的方法会很好地起作用,因为它被视为其他任何Spring
Bean。如果您的实现片段bean需要特殊的接线,则可以声明bean并根据上一节中描述的约定对其进行命名。然后,基础结构通过名称引用手动定义的bean定义,而不是自己创建一个。以下示例显示如何手动连接自定义实现:
*例子32.手工连接定制实现*
<repositories base-package="com.acme.repository" />
<beans:bean id="userRepositoryImpl" class="…">
beans:bean>
当您要自定义基本存储库行为时,上一节中描述的方法需要自定义每个存储库接口,以使所有存储库均受到影响。要改为更改所有存储库的行为,您可以创建一个实现,以扩展特定于持久性技术的存储库基类。然后,该类充当存储库代理的自定义基类,如以下示例所示:
*例子33.定制存储库基类*
class MyRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> {
private final EntityManager entityManager;
MyRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
// Keep the EntityManager around to used from the newly introduced methods.
this.entityManager = entityManager;
}
@Transactional
public <S extends T> S save(S entity) {
// implementation goes here
}
}
该类需要具有特定于存储库的存储库工厂实现使用的超类的构造函数。如果存储库基类具有多个构造函数,请重写一个构造函数,并EntityInformation加上一个商店特定的基础结构对象(例如EntityManager或模板类)。 |
---|
最后一步是使Spring
Data基础结构了解定制的存储库基类。在Java配置中,可以通过使用批注的repositoryBaseClass属性来执行此操作@Enable${store}Repositories,如以下示例所示:
*例子34.使用JavaConfig配置一个定制的存储库基类*
@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }
XML名称空间中提供了相应的属性,如以下示例所示:
例子35.使用XML配置一个定制的存储库基类
base-class="….MyRepositoryImpl" /> 由存储库管理的实体是聚合根。在域驱动设计应用程序中,这些聚合根通常发布域事件。Spring 每次调用Spring Data存储库的save(…)一种方法时,就会调用这些方法。 本节记录了一组Spring Data扩展,这些扩展可在各种上下文中启用Spring Querydsl是一个框架,可通过其流畅的API来构造静态类型的类似SQL的查询。 几个Spring 要使用Querydsl支持,请扩展QuerydslPredicateExecutor存储库界面,如以下示例所示 支持存储库编程模型的Spring Data模块附带了各种Web支持。与Web相关的组件要求Spring 该@EnableSpringDataWebSupport批注注册几个组件,我们将在一个位讨论。它还将在类路径上检测Spring 另外,如果您使用XML配置,请注册SpringDataWebConfiguration或注册HateoasAwareSpringDataWebConfiguration为Spring 基本网络支持 上一节中显示的配置注册了一些基本组件: 一个DomainClassConverter让仓库管理领域类的Spring HandlerMethodArgumentResolverSpring DomainClassConverter 使用DomainClassConverter,您可以直接在Spring 例子41.在方法签名中使用域类型的Spring MVC控制器 如您所见,该方法User直接接收一个实例,不需要进一步的查找。可以通过让Spring 用于分页和排序的HandlerMethodArgumentResolvers 上一节中显示的配置代码段还注册PageableHandlerMethodArgumentResolver以及的实例SortHandlerMethodArgumentResolver。注册启用Pageable并Sort作为有效的控制器方法参数,如以下示例所示: 例子42.使用Pageable作为控制器方法参数 前面的方法签名使Spring MVC尝试Pageable使用以下默认配置从请求参数派生实例: 要定制此行为,请分别注册一个实现该PageableHandlerMethodArgumentResolverCustomizer接口或该SortHandlerMethodArgumentResolverCustomizer接口的bean 。它的customize()方法被调用,让您更改设置,如以下示例所示: 如果设置现有属性MethodArgumentResolver不足以实现您的目的,请扩展SpringDataWebConfiguration或扩展启用HATEOAS的等效项,覆盖pageableResolver()或sortResolver()方法,然后导入自定义的配置文件,而不使用@Enable注释。 如果您需要从请求中解析多个Pageable或Sort实例(例如,对于多个表),则可以使用Spring的@Qualifier注释将一个或另一个进行区分。然后,请求参数必须以开头${qualifier}_。以下示例显示了生成的方法签名: 你有填充thing1_page和thing2_page等。 Pageable传递给该方法的默认值等效于a,PageRequest.of(0, 超媒体对分页的支持 Spring 例子43.使用PagedResourcesAssembler作为控制器方法参数 如上例所示启用配置,可以将PagedResourcesAssembler其用作控制器方法参数。调用toResources(…)它具有以下效果: 的内容Page成为PagedResources实例的内容。 所述PagedResources对象获得一个PageMetadata附加实例,并且它填充了从信息Page和底层PageRequest。 将PagedResources可能会prev和next连接链路,根据页面的状态。链接指向方法映射到的URI。添加到该方法的分页参数与的设置匹配,PageableHandlerMethodArgumentResolver以确保以后可以解析链接。 假设数据库中有30个Person实例。现在,您可以触发一个请求(),并查看类似于以下内容的输出:GET http://localhost:8080/persons 您会看到汇编器生成了正确的URI,并且还选择了默认配置以将参数解析Pageable为即将到来的请求。这意味着,如果您更改该配置,则链接将自动遵循更改。默认情况下,汇编器指向调用它的控制器方法,但是可以通过传递一个自定义来自定义该自定义方法Link,以用作建立分页链接的基础,这会使该PagedResourcesAssembler.toResource(…)方法过载。 Web数据绑定支持 通过使用JSONPath表达式(需要Jayway 在前面的示例中示出的类型可以用作一个Spring 如[投影]中所述,支持嵌套投影。如果该方法返回复杂的非接口类型,ObjectMapper则使用Jackson 来映射最终值。 对于Spring 有关更多信息,请参见规范的Spring Data Querydsl Web支持 对于那些具有QueryDSL集成的商店,可以从Request查询字符串中包含的属性派生查询。 考虑以下查询字符串: ?firstname=Dave&lastname=Matthews 给定User前面示例中的对象,可以使用将查询字符串解析为以下值QuerydslPredicateArgumentResolver。 QUser.user.firstname.eq(“Dave”).and(QUser.user.lastname.eq(“Matthews”)) @QuerydslPredicate在方法签名中添加一个即可使用Predicate,可以使用来运行QuerydslPredicateExecutor。 以下示例显示了如何@QuerydslPredicate在方法签名中使用: 默认绑定如下: Object关于的简单属性eq。 Object像属性一样的集合contains。 Collection关于的简单属性in。 这些绑定可以通过Java 8 的bindings属性@QuerydslPredicate或通过使用Java 8 default 如果您使用Spring 假设您有一个data.json包含以下内容的文件: 例子45.用JSON定义的数据 您可以使用Spring Data 例子46.声明一个Jackson存储库填充器 前面的声明使data.json文件由Jackson读取并反序列化ObjectMapper。 通过检查_classJSON文档的属性来确定将JSON对象解组到的类型。基础结构最终选择适当的存储库来处理反序列化的对象。 要改为使用XML定义应使用存储库填充的数据,可以使用unmarshaller-populator元素。您可以将其配置为使用Spring 例子47.声明一个解组存储库填充器(使用JAXB) 参考文件 本章包括Elasticsearch存储库实现的详细信息。 Spring Data repositories如创建存储库实例中所述,使用元素来查找Spring 示例48.使用命名空间设置Elasticsearch存储库 使用Transport Client或Node Client元素Elasticsearch Server在上下文中注册的实例。 例子49.使用命名空间的传输客户端 例子50.使用命名空间的Node Client Spring Data 上面设置了一个配置Embedded Elasticsearch 还可以使用CDI功能设置Spring Data Elasticsearch存储库。 Elasticsearch模块支持所有基本的查询构建功能,如String,Abstract,Criteria或从方法名称派生。 声明的查询 从方法名称派生查询并不总是足够的,并且/或者可能导致方法名称不可读。在这种情况下,可能会使用任何一种@Query注解(请参阅使用@Query注解)。 通常,Elasticsearch的查询创建机制按Query方法中所述工作。这是Elasticsearch查询方法转换成的简短示例: 上面的方法名称将转换为以下Elasticsearch json查询 Elasticsearch支持的关键字列表如下所示。 本章涵盖无法通过存储库接口直接访问的对Elasticsearch操作的其他支持。建议将这些操作添加为自定义实现,如Spring Filter Builder可以提高查询速度。 Elasticsearch有一个滚动API,用于以块为单位获取较大的结果集。ElasticsearchTemplate具有startScroll和continueScroll方法,可以按如下方式使用。 ElasticsearchTemplate 此外,还具有将扫描和滚动操作包装到CloseableIterator中的stream方法。 该 该 该 支持的查询关键字 下表列出了Spring 支持的查询返回类型 下表列出了Spring 1。查看XML配置 版本3.1.5.RELEASE1.7。从汇总根发布事件
Data提供了一个称为的注释@DomainEvents,您可以在聚合根的方法上使用该注释,以使该发布尽可能容易,如以下示例所示:*例子36.从聚合根公开域事件*
class AnAggregateRoot {
@DomainEvents
Collection<Object> domainEvents() {
// … return events you want to get published here
}
@AfterDomainEventPublication
void callbackMethod() {
// … potentially clean up domain events list
}
}
使用的方法@DomainEvents可以返回单个事件实例或事件的集合。它不能接受任何参数。
在发布所有事件之后,我们将使用注释方法@AfterDomainEventPublication。它可以用来潜在地清除要发布的事件列表(以及其他用途)。
1.8。Spring数据扩展
Data使用。当前,大多数集成都针对Spring MVC。1.8.1。Querydsl扩展
Data模块通过提供与Querydsl的集成QuerydslPredicateExecutor,如以下示例所示:*例子37. QuerydslPredicateExecutor接口*
public interface QuerydslPredicateExecutor<T> {
Optional<T> findById(Predicate predicate);
Iterable<T> findAll(Predicate predicate);
long count(Predicate predicate);
boolean exists(Predicate predicate);
// … more functionality omitted.
}
查找并返回与匹配的单个实体Predicate。
查找并返回与匹配的所有实体Predicate。
返回与匹配的实体数Predicate。
返回匹配Predicate存在的实体。
*例子38.存储库上的Querydsl集成*
interface UserRepository extends CrudRepository\<User, Long\>,
QuerydslPredicateExecutor\<User\> {
}
前面的示例使您可以使用Querydsl Predicate实例编写类型安全查询,如以下示例所示:
Predicate predicate = user.firstname.equalsIgnoreCase("dave")
.and(user.lastname.startsWithIgnoreCase("mathews"));
userRepository.findAll(predicate);
1.8.2。网路支援
本部分包含Spring Data Web支持的文档,该文档在Spring Data Commons的当前(和更高版本)中实现。随着新引入的支持发生了很多变化,我们将以前行为的文档保存在[web.legacy]中。
MVC JAR位于类路径上。其中一些甚至提供与Spring
HATEOAS的集成。通常,通过使用@EnableSpringDataWebSupportJavaConfig配置类中的注释来启用集成支持,如以下示例所示:*例子39.启用Spring Data Web支持*
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration {}
HATEOAS,并为其注册集成组件(如果存在)。
Bean,如以下示例(针对SpringDataWebConfiguration)所示:*例子40.在XML中启用Spring Data Web支持*
<bean class="org.springframework.data.web.config.SpringDataWebConfiguration"
/>
<bean
class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration"
/>
MVC的决心情况下,从请求参数或路径变量。
MVC实现的实现Pageable以及Sort来自请求参数的实例。
MVC控制器方法签名中使用域类型,从而无需通过存储库手动查找实例,如以下示例所示:@Controller
@RequestMapping("/users")
class UserController {
@RequestMapping("/{id}")
String showUserForm(@PathVariable("id") User user, Model model) {
model.addAttribute("user", user);
return "userForm";
}
}
MVC首先将路径变量转换为id域类的类型并最终通过调用findById(…)为该域类型注册的存储库实例来访问该实例来解析该实例。
当前,该存储库必须实现CrudRepository才有资格被发现以进行转换。
@Controller
@RequestMapping("/users")
class UserController {
private final UserRepository repository;
UserController(UserRepository repository) {
this.repository = repository;
}
@RequestMapping
String showUsers(Model model, Pageable pageable) {
model.addAttribute("users", repository.findAll(pageable));
return "users";
}
}
表1.为Pageable实例评估的请求参数
page
您要检索的页面。0索引,默认为0。
size
您要检索的页面大小。默认为20
sort
应该以格式排序的属性property,property(,ASC|DESC)。默认排序方向为升序。sort如果要切换方向,请使用多个参数,例如?sort=firstname&sort=lastname,asc。
@Bean SortHandlerMethodArgumentResolverCustomizer sortCustomizer() {
return s -> s.setPropertyDelimiter("<-->");
}
String showUsers(Model model,
@Qualifier("thing1") Pageable first,
@Qualifier("thing2") Pageable second) { … }
20)但可以使用参数@PageableDefault上的注释进行自定义Pageable。
HATEOAS附带了一个表示模型类(PagedResources),该类允许Page使用必要的Page元数据和链接来丰富实例的内容,以使客户端可以轻松浏览页面。Page到a的转换PagedResources是通过Spring
HATEOAS ResourceAssembler接口(称为)的实现完成的PagedResourcesAssembler。以下示例显示如何将a 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);
}
}
{ "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
}
}
JsonPath或XPath表达式(需要XmlBeam)),可以使用Spring
Data投影(在[projections]中描述)来绑定传入的请求有效负载,如以下示例所示:*例子44.使用JSONPath或XPath表达式的HTTP有效负载绑定*
@ProjectedPayload
public interface UserPayload {
@XBRead("//firstname")
@JsonPath("$..firstname")
String getFirstname();
@XBRead("/lastname")
@JsonPath({ "$.lastname", "$.user.lastname" })
String getLastname();
}
MVC处理程序方法参数或通过使用ParameterizedTypeReference上的一个RestTemplate的方法。前面的方法声明将尝试firstname在给定文档中的任何地方查找。该lastnameXML查询是对输入文档的顶层进行。的JSON变体lastname首先尝试顶层,但如果前者未返回值,则还尝试lastname嵌套在user子文档中。这样,无需客户端调用公开的方法即可轻松缓解源文档结构的更改(通常是基于类的有效负载绑定的缺点)。
MVC,必要的转换器在@EnableSpringDataWebSupport活动时会立即自动注册,并且所需的依赖项在类路径上可用。要用于RestTemplate,请注册ProjectingJackson2HttpMessageConverter(JSON)或XmlBeamHttpMessageConverter手动。
Examples存储库中的Web投影示例。
@EnableSpringDataWebSupport当在类路径上找到Querydsl时 ,该功能将与一起自动启用。
类型信息通常从方法的返回类型中解析。由于该信息不一定与域类型匹配,因此使用的root属性可能是一个好主意QuerydslPredicate。
@Controller
class UserController {
@Autowired UserRepository repository;
@RequestMapping(value = "/", method = RequestMethod.GET)
String index(Model model, @QuerydslPredicate(root = User.class) Predicate
predicate,
Pageable pageable, @RequestParam MultiValueMap<String, String> parameters) {
model.addAttribute("users", repository.findAll(predicate, pageable));
return "index";
}
}
解析查询字符串参数匹配Predicate的User。
methods并将QuerydslBinderCustomizer方法添加到存储库接口进行自定义。interface UserRepository extends CrudRepository<User, String>,
QuerydslPredicateExecutor<User>,
QuerydslBinderCustomizer<QUser> {
@Override
default void customize(QuerydslBindings bindings, QUser user) {
bindings.bind(user.username).first((path, value) -> path.contains(value))
bindings.bind(String.class)
.first((StringPath path, String value) -> path.containsIgnoreCase(value));
bindings.excluding(user.password);
}
}
QuerydslPredicateExecutor提供对的特定查找器方法的访问Predicate。
QuerydslBinderCustomizer系统会自动获取在存储库界面上定义的定义和快捷方式@QuerydslPredicate(bindings=…)。
将username属性的绑定定义为简单contains绑定。
将String属性的默认绑定定义为不区分大小写的contains匹配。
password从Predicate分辨率中排除该属性。
1.8.3。存储库填充器
JDBC模块,则可能熟悉DataSource使用SQL脚本填充a的支持。尽管它不使用SQL作为数据定义语言,因为它必须独立于存储,因此可以在存储库级别使用类似的抽象。因此,填充器支持XML(通过Spring的OXM抽象)和JSON(通过Jackson)来定义用于填充存储库的数据。[ { "_class" : "com.acme.Person",
"firstname" : "Dave",
"lastname" : "Matthews" },
{ "_class" : "com.acme.Person",
"firstname" : "Carter",
"lastname" : "Beauford" } ]
Commons中提供的存储库名称空间的populator元素来填充存储库。要将前面的数据填充到PersonRepository中,请声明类似于以下内容的填充器:
<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:jackson2-populator locations="classpath:data.json" />
beans>
OXM中可用的XML
marshaller选项之一。有关详细信息,请参见Spring参考文档。以下示例显示如何使用JAXB解组存储库填充器:
<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>
2. Elasticsearch存储库
2.1。介绍
2.1.1。Spring命名空间
Elasticsearch模块包含一个自定义名称空间,允许定义存储库bean以及用于实例化的元素ElasticsearchServer。
Data存储库。
<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>
<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>
<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">
2.1.2。基于注释的配置
Elasticsearch存储库支持不仅可以通过XML名称空间激活,还可以通过JavaConfig使用注释。*例子51.使用JavaConfig的Spring Data Elasticsearch存储库*
@Configuration
@EnableElasticsearchRepositories(basePackages =
"org/springframework/data/elasticsearch/repositories")
static class Config {
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
}
}
Server,其由所使用的ElasticsearchTemplate。Spring Data Elasticsearch
Repository是使用@EnableElasticsearchRepositories注释激活的,该注释实质上具有与XML名称空间相同的属性。如果未配置任何基本程序包,它将使用配置类所在的程序包。2.1.3。使用CDI的Elasticsearch存储库
*例子52.使用JavaConfig的Spring Data Elasticsearch存储库*
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;
}
}
2.2。查询方法
2.2.1。查询查询策略
2.2.2。查询创建
*例子53.从方法名称创建查询*
public interface BookRepository extends Repository<Book, String>
{
List<Book> findByNameAndPrice(String name, Integer price);
}
{ "bool" :
{ "must" :
[
{ "field" : {"name" : "?"} },
{ "field" : {"price" : "?"} }
]
}
}
表2.方法名称中受支持的关键字
关键词
样品
Elasticsearch查询字符串
And
findByNameAndPrice
{“bool” : {“must” : [ {“field” : {“name” : “?”}}, {“field” : {“price” : “?”}} ]}}
Or
findByNameOrPrice
{“bool” : {“should” : [ {“field” : {“name” : “?”}}, {“field” : {“price” : “?”}} ]}}
Is
findByName
{“bool” : {“must” : {“field” : {“name” : “?”}}}}
Not
findByNameNot
{“bool” : {“must_not” : {“field” : {“name” : “?”}}}}
Between
findByPriceBetween
{“bool” : {“must” : {“range” : {“price” : {“from” : ?,“to” : ?,“include_lower” : true,“include_upper” : true}}}}}
LessThanEqual
findByPriceLessThan
{“bool” : {“must” : {“range” : {“price” : {“from” : null,“to” : ?,“include_lower” : true,“include_upper” : true}}}}}
GreaterThanEqual
findByPriceGreaterThan
{“bool” : {“must” : {“range” : {“price” : {“from” : ?,“to” : null,“include_lower” : true,“include_upper” : true}}}}}
Before
findByPriceBefore
{“bool” : {“must” : {“range” : {“price” : {“from” : null,“to” : ?,“include_lower” : true,“include_upper” : true}}}}}
After
findByPriceAfter
{“bool” : {“must” : {“range” : {“price” : {“from” : ?,“to” : null,“include_lower” : true,“include_upper” : true}}}}}
Like
findByNameLike
{“bool” : {“must” : {“field” : {“name” : {“query” : “?*”,“analyze_wildcard” : true}}}}}
StartingWith
findByNameStartingWith
{“bool” : {“must” : {“field” : {“name” : {“query” : “?*”,“analyze_wildcard” : true}}}}}
EndingWith
findByNameEndingWith
{“bool” : {“must” : {“field” : {“name” : {“query” : “*?”,“analyze_wildcard” : true}}}}}
Contains/Containing
findByNameContaining
{“bool” : {“must” : {“field” : {“name” : {“query” : “?”,“analyze_wildcard” : true}}}}}
In
findByNameIn(Collection
{“bool” : {“must” : {“bool” : {“should” : [ {“field” : {“name” : “?”}}, {“field” : {“name” : “?”}} ]}}}}
NotIn
findByNameNotIn(Collection
{“bool” : {“must_not” : {“bool” : {“should” : {“field” : {“name” : “?”}}}}}}
Near
findByStoreNear
Not Supported Yet !
True
findByAvailableTrue
{“bool” : {“must” : {“field” : {“available” : true}}}}
False
findByAvailableFalse
{“bool” : {“must” : {“field” : {“available” : false}}}}
OrderBy
findByAvailableTrueOrderByNameDesc
{“sort” : [{ “name” : {“order” : “desc”} }],“bool” : {“must” : {“field” : {“available” : true}}}}
2.2.3。使用@Query注释
*例子54.使用\@Query注释声明方法的查询*
public interface BookRepository extends ElasticsearchRepository<Book, String>
{
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"name\" : \"?0\"}}}}")
Page<Book> findByName(String name,Pageable pageable);
}
3.杂项Elasticsearch操作支持
Data
Repositories的自定义实现中所述。3.1。筛选器生成器
private ElasticsearchTemplate elasticsearchTemplate;
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFilter(boolFilter().must(termFilter("id", documentId)))
.build();
Page<SampleEntity> sampleEntities =
elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
3.2。使用滚动查看大结果集
*例子55.使用startScroll和continueScroll*
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withIndices(INDEX_NAME)
.withTypes(TYPE_NAME)
.withFields("message")
.withPageable(PageRequest.of(0, 10))
.build();
Page<SampleEntity> scroll = elasticsearchTemplate.startScroll(1000,
searchQuery, SampleEntity.class);
String scrollId = ((ScrolledPage) scroll).getScrollId();
List<SampleEntity> sampleEntities = new ArrayList<>();
while (scroll.hasContent()) {
sampleEntities.addAll(scroll.getContent());
scrollId = ((ScrolledPage) scroll).getScrollId();
scroll = elasticsearchTemplate.continueScroll(scrollId, 1000,
SampleEntity.class);
}
elasticsearchTemplate.clearScroll(scrollId);
*例子56.使用流*
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withIndices(INDEX_NAME)
.withTypes(TYPE_NAME)
.withFields("message")
.withPageable(PageRequest.of(0, 10))
.build();
CloseableIterator<SampleEntity> stream =
elasticsearchTemplate.stream(searchQuery, SampleEntity.class);
List<SampleEntity> sampleEntities = new ArrayList<>();
while (stream.hasNext()) {
sampleEntities.add(stream.next());
}
附录
附录A:命名空间参考
Data存储库基础结构的设置。最重要的属性是base-package,它定义用于扫描Spring
Data存储库接口的包。请参阅“ XML配置 ”。下表描述了
表3.属性
名称
描述
base-package
定义要扫描的软件包,以查找*Repository在自动检测模式下扩展的存储库接口(实际接口由特定的Spring Data模块确定)。配置包下面的所有包也将被扫描。允许使用通配符。
repository-impl-postfix
定义后缀以自动检测自定义存储库实现。名称以配置的后缀结尾的类被视为候选。默认为Impl。
query-lookup-strategy
确定用于创建查找器查询的策略。有关详细信息,请参见“ 查询查找策略 ”。默认为create-if-not-found。
named-queries-location
定义搜索包含外部定义查询的属性文件的位置。
consider-nested-repositories
是否应考虑嵌套的存储库接口定义。默认为false。
附录B:填充器名称空间参考
表4.属性
名称
描述
locations
从哪里可以找到要从存储库读取对象的文件,应在其中填充。
附录C:存储库查询关键字
Data存储库查询派生机制通常支持的关键字。但是,请参阅商店特定的文档以获取受支持关键字的确切列表,因为特定商店可能不支持此处列出的某些关键字。
表5.查询关键字
逻辑关键字
关键字表达
AND
And
OR
Or
AFTER
After, IsAfter
BEFORE
Before, IsBefore
CONTAINING
Containing,IsContaining,Contains
BETWEEN
Between, IsBetween
ENDING_WITH
EndingWith,IsEndingWith,EndsWith
EXISTS
Exists
FALSE
False, IsFalse
GREATER_THAN
GreaterThan, IsGreaterThan
GREATER_THAN_EQUALS
GreaterThanEqual, IsGreaterThanEqual
IN
In, IsIn
IS
Is、、Equals(或没有关键字)
IS_EMPTY
IsEmpty, Empty
IS_NOT_EMPTY
IsNotEmpty, NotEmpty
IS_NOT_NULL
NotNull, IsNotNull
IS_NULL
Null, IsNull
LESS_THAN
LessThan, IsLessThan
LESS_THAN_EQUAL
LessThanEqual, IsLessThanEqual
LIKE
Like, IsLike
NEAR
Near, IsNear
NOT
Not, IsNot
NOT_IN
NotIn, IsNotIn
NOT_LIKE
NotLike, IsNotLike
REGEX
Regex,MatchesRegex,Matches
STARTING_WITH
StartingWith,IsStartingWith,StartsWith
TRUE
True, IsTrue
WITHIN
Within, IsWithin
附录D:储存库查询返回类型
Data存储库通常支持的返回类型。但是,请参阅商店特定的文档以获取受支持的退货类型的确切列表,因为特定商店可能不支持此处列出的某些类型。
地理空间类型(如GeoResult,GeoResults,和GeoPage)是仅适用于支持地理空间查询的数据存储。
表6.查询返回类型
返回类型
描述
void
表示没有返回值。
原语
Java基元。
包装类型
Java包装器类型。
T
唯一实体。期望查询方法最多返回一个结果。如果找不到结果,null则返回。多个结果触发IncorrectResultSizeDataAccessException。
Iterator
的Iterator。
Collection
一Collection。
List
一List。
Optional
Java 8或Guava Optional。期望查询方法最多返回一个结果。如果没有找到结果,Optional.empty()或者Optional.absent()返回结果。多个结果触发IncorrectResultSizeDataAccessException。
Option
Scala或Javaslang Option类型。语义上与Optional前面描述的Java 8相同。
Stream
Java 8 Stream。
Future
一Future。期望使用方法进行注释,@Async并且需要启用Spring的异步方法执行功能。
CompletableFuture
Java 8 CompletableFuture。期望使用方法进行注释,@Async并且需要启用Spring的异步方法执行功能。
ListenableFuture
一org.springframework.util.concurrent.ListenableFuture。期望使用方法进行注释,@Async并且需要启用Spring的异步方法执行功能。
Slice
一定大小的数据块,用于指示是否有更多可用数据。需要一个Pageable方法参数。
Page
A Slice with additional information, such as the total number of results. Requires a Pageable method parameter.
GeoResult
A result entry with additional information, such as the distance to a reference location.
GeoResults
A list of GeoResult
GeoPage
A Page with GeoResult
Mono
A Project Reactor Mono emitting zero or one element using reactive repositories. Expects the query method to return one result at most. If no result is found, Mono.empty() is returned. More than one result triggers an IncorrectResultSizeDataAccessException.
Flux
A Project Reactor Flux emitting zero, one, or many elements using reactive repositories. Queries returning Flux can emit also an infinite number of elements.
Single
Single使用反应性存储库发出单个元素的RxJava 。期望查询方法最多返回一个结果。如果找不到结果,Mono.empty()则返回。多个结果触发IncorrectResultSizeDataAccessException。
Maybe
Maybe使用反应性存储库发出零个或一个元素的RxJava 。期望查询方法最多返回一个结果。如果找不到结果,Mono.empty()则返回。多个结果触发IncorrectResultSizeDataAccessException。
Flowable
Flowable使用反应性存储库发出零个,一个或多个元素的RxJava 。返回的查询Flowable也可以发出无限数量的元素。
最后更新于2019-02-13 09:54:22 MEZ