提交 4903b17a 编写于 作者: 茶陵後's avatar 茶陵後 👍

#15 spring data 推送

上级 3a0aabd3
......@@ -132,7 +132,7 @@ class PersonObjectInstantiator implements ObjectInstantiator {
3. 如果属性是可变的,我们直接设置字段。
4. 如果该属性是不可变的,那么我们将使用持久化操作使用的构造函数(参见[Object creation](#mapping.object-creation))来创建实例的副本。
4. 如果该属性是不可变的,那么我们将使用持久化操作使用的构造函数(参见[对象创建](#mapping.object-creation))来创建实例的副本。
5. 默认情况下,我们直接设置字段的值。
......@@ -261,11 +261,11 @@ class Person {
* *提供一个 All-Args 构造器*——即使你不能或不想将实体建模为不可变的值,提供一个构造函数仍然有价值,该构造函数将实体的所有属性作为参数,包括可变的属性,因为这允许对象映射跳过属性总体以获得最佳性能。
* *Use factory methods instead of overloaded constructors to avoid `@PersistenceConstructor`*—有了最佳性能所需的全参数构造函数,我们通常希望公开更多的应用程序用例特定的构造函数,这些构造函数省略了自动生成的标识符等内容。使用静态工厂方法来公开 All-Args 构造函数的这些变体是一种已有的模式。
* * 使用工厂方法而不是重载的构造函数来避免`@PersistenceConstructor`*——使用最佳性能所需的全参数构造函数,我们通常希望公开更多的应用程序用例特定的构造函数,这些构造函数省略了自动生成的标识符等内容。使用静态工厂方法来公开 All-Args 构造函数的这些变体是一种已有的模式。
* *确保遵守允许使用生成的实例器和属性访问器类的约束*
* *For identifiers to be generated, still use a final field in combination with an all-arguments persistence constructor (preferred) or a `with…` method*
* * 对于要生成的标识符,仍然使用与全参数持久性构造函数(首选)或`with…`方法 * 相结合的最终字段
* *使用 Lombok 避免样板代码*—因为持久性操作通常需要一个构造函数来接受所有参数,所以它们的声明变成了对字段分配的样板参数的繁琐重复,而使用 Lombok 的`@AllArgsConstructor`可以最好地避免这种重复。
......@@ -322,7 +322,7 @@ Spring 数据模块通常支持持有不同值的重写属性。从编程模型
2. 如何表示你的数据存储中的属性?对不同的值使用相同的字段/列名称通常会导致数据损坏,因此你应该使用显式的字段/列名称对至少一个属性进行注释。
3. 使用`@AccessType(PROPERTY)`不能作为超级属性,如果不对 setter 实现进行任何进一步的假设,则通常不能进行设置。
3. 使用`@AccessType(PROPERTY)`不能作为超级属性,如果不对 setter 实现做任何进一步的假设,通常不能进行设置。
### 3.4. Kotlin 支持
......@@ -415,7 +415,7 @@ public final class SubType extends SuperType {
}
```
`SubType`上的 getters 和 setters 只设置`SubType.field`而不是`SuperType.field`。在这种安排中,使用构造函数是设置`SuperType.field`的唯一缺省方法。通过`this.SuperType.field = …``SubType`添加一个方法来设置`SuperType.field`是可能的,但不属于受支持的约定。属性重写在一定程度上造成了冲突,因为这些属性共享相同的名称,但可能表示两个不同的值。我们通常建议使用不同的属性名称。
`SubType`上的 getters 和 setters 只设置`SubType.field`,而不是`SuperType.field`。在这种安排中,使用构造函数是设置`SuperType.field`的唯一缺省方法。将方法添加到`SubType`以通过`this.SuperType.field = …`设置`SuperType.field`是可能的,但不属于受支持的约定。属性重写在一定程度上造成了冲突,因为这些属性共享相同的名称,但可能表示两个不同的值。我们通常建议使用不同的属性名称。
Spring 数据模块通常支持持有不同值的重写属性。从编程模型的角度来看,有几点需要考虑:
......@@ -429,12 +429,12 @@ Spring 数据模块通常支持持有不同值的重写属性。从编程模型
Spring 数据存储库抽象的目标是显著减少为各种持久性存储实现数据访问层所需的样板代码的数量。
| |*Spring Data repository documentation and your module*<br/><br/>本章解释了 Spring 数据存储库的核心概念和接口。<br/>本章中的信息是从 Spring 数据共享模块中提取的。<br/>它使用了配置以及 Java 持久性 API( JPA)模块的代码示例。<br/>你应该调整 XML 名称空间声明和要扩展的类型,使其与你所使用的特定模块的等同物。“[名称空间引用](#repositories.namespace-reference)”涵盖了 XML 配置,该配置在支持存储库 API 的所有 Spring 数据模块中都受到支持。“[存储库查询关键字](#repository-query-keywords)”一般涵盖了存储库抽象支持的查询方法关键字。<br/>有关模块的具体功能的详细信息,请参见本文档中有关该模块的章节。|
| |*Spring Data repository documentation and your module*<br/><br/>本章解释了 Spring 数据存储库的核心概念和接口。<br/>本章中的信息是从 Spring 数据共享模块中提取的。<br/>它使用了配置以及 Java 持久性 API( JPA)模块的代码示例。<br/>你应该调整 XML 名称空间声明和要扩展的类型,使其与你所使用的特定模块的等同物。“[名称空间引用](#repositories.namespace-reference)”涵盖了 XML 配置,该配置在支持存储库 API 的所有 Spring 数据模块中都受到支持。“[存储库查询关键字](#repository-query-keywords)”一般涵盖了存储库抽象支持的查询方法关键字。<br/>有关模块特定功能的详细信息,请参见本文档有关该模块的章节。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
### 4.1.核心概念
Spring 数据存储库抽象中的中心接口是`Repository`。它把要管理的域类以及域类的 ID 类型作为类型参数。这个接口主要充当一个标记接口,用于捕获要使用的类型,并帮助你发现扩展这个类型的接口。[“粗栓剂”](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html)接口为正在管理的实体类提供了复杂的增删改查功能。
Spring 数据存储库抽象中的中心接口是`Repository`。它把要管理的域类以及域类的 ID 类型作为类型参数。这个接口主要充当一个标记接口,用于捕获要使用的类型,并帮助你发现扩展这个类型的接口。[`CrudRepository`](https://DOCS. Spring.io/ Spring-data/commons/DOCS/current/api/org/springframework/data/repository/crudrepository.html)接口为所管理的实体类提供了复杂的增删改查功能。
例 5。`CrudRepository`接口
......@@ -468,7 +468,7 @@ public interface CrudRepository<T, ID> extends Repository<T, ID> {
| |我们还提供了特定于持久性技术的抽象,例如`JpaRepository``MongoRepository`<br/>这些接口扩展了`CrudRepository`,并且除了比较通用的持久性技术之外,还公开了底层持久性技术的功能,这些接口与持久性技术无关,例如`CrudRepository`。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
`CrudRepository`之上,有一个[“pagingandsortingrepository”](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/PagingAndSortingRepository.html)抽象,它添加了其他方法,以方便对实体的分页访问:
`CrudRepository`之上,有一个[`PagingAndSortingRepository`](https://DOCS. Spring.io/ Spring-data/commons/DOCS/current/api/org/springframework/data/repository/pagingandsortingrepository.html)抽象,它添加了额外的方法,以简化对实体的分页访问:
例 6。`PagingAndSortingRepository`接口
......@@ -560,7 +560,7 @@ interface UserRepository extends CrudRepository<User, Long> {
JPA 名称空间在本例中使用。如果你对任何其他存储使用存储库抽象,则需要将其更改为存储模块的适当名称空间声明。换句话说,你应该使用`jpa`来交换,例如,`mongodb`。
另外,请注意,JavaConfig 变体不会显式地配置包,因为默认情况下使用的是带注释的类的包。要定制要扫描的包,请使用数据存储特定存储库的`@Enable${store}Repositories`-注释的`basePackage…`属性之一。
另外,请注意,JavaConfig 变体不会显式地配置包,因为默认情况下使用的是带注释的类的包。要定制要扫描的包,请使用数据存储特定存储库的`basePackage…`-注释的`@Enable${store}Repositories`属性之一。
4. 注入存储库实例并使用它,如以下示例所示:
......@@ -595,14 +595,14 @@ interface UserRepository extends CrudRepository<User, Long> {
#### 4.3.1.微调存储库定义
通常,存储库接口扩展`Repository``CrudRepository``PagingAndSortingRepository`。或者,如果不想扩展 Spring 数据接口,也可以使用`@RepositoryDefinition`对存储库接口进行注释。扩展`CrudRepository`公开了一组完整的方法来操作你的实体。如果你希望对要公开的方法有所选择,请将要公开的方法从`CrudRepository`复制到你的域存储库中。
通常,存储库接口扩展`Repository``CrudRepository``PagingAndSortingRepository`。或者,如果不想扩展 Spring 数据接口,也可以`@RepositoryDefinition`注释存储库接口。扩展`CrudRepository`公开了一组完整的方法来操作你的实体。如果你希望对要公开的方法有所选择,那么可以将要公开的方法从`CrudRepository`复制到你的域存储库中。
| |这样做可以让你在所提供的 Spring 数据存储库功能之上定义自己的抽象。|
|---|-------------------------------------------------------------------------------------------------------------|
下面的示例显示了如何有选择地公开增删改查方法(在本例中为 `findbyid’和`save`):
下面的示例显示了如何选择性地公开增删改查方法(在本例中,是`findById``save`):
例 9。有选择地公开增删改查方法
例 9。有选择地暴露增删改查方法
```
@NoRepositoryBean
......@@ -618,7 +618,7 @@ interface UserRepository extends MyBaseRepository<User, Long> {
}
```
在前面的示例中,你为所有域存储库定义了一个公共的基本接口,并公开了`findById(…)`以及`save(…)`,这些方法被路由到 Spring 数据提供的你选择的存储库的基本存储库实现(例如,如果你使用 JPA,实现是`SimpleJpaRepository`),因为它们匹配`CrudRepository`中的方法签名。因此`UserRepository`现在可以保存用户,通过 ID 查找单个用户,并触发查询以通过电子邮件地址查找`Users`。
在前面的示例中,你为所有域存储库定义了一个公共的基本接口,并公开了`findById(…)`以及`save(…)`,这些方法被路由到你选择的存储库的基础存储库实现中,该存储库由 Spring 数据提供(例如,如果你使用 JPA,实现是`SimpleJpaRepository`),因为它们匹配`CrudRepository`中的方法签名。因此`UserRepository`现在可以保存用户,通过 ID 查找单个用户,并触发查询以通过电子邮件地址查找`Users`
| |中间存储库接口用`@NoRepositoryBean`注释。<br/>确保将该注释添加到所有存储库接口中,其中 Spring 数据不应在运行时为其创建实例。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
......@@ -629,7 +629,7 @@ interface UserRepository extends MyBaseRepository<User, Long> {
1. 如果存储库定义[扩展特定于模块的存储库](#repositories.multiple-modules.types),则它是特定 Spring 数据模块的有效候选者。
2. 如果域类是[使用特定于模块的类型注释](#repositories.multiple-modules.annotations),则它是特定 Spring 数据模块的有效候选者。 Spring 数据模块要么接受第三方注释(例如 JPA 的`@Entity`),要么提供自己的注释(例如`@Document`用于 Spring Data MongoDB 和 Spring Data ElasticSearch)。
2. 如果域类是[使用特定于模块的类型注释](#repositories.multiple-modules.annotations),则它是特定 Spring 数据模块的有效候选者。 Spring 数据模块要么接受第三方注释(例如 JPA 的`@Entity`),要么提供自己的注释(例如用于 Spring Data MongoDB 和 Spring Data ElasticSearch 的`@Document`)。
下面的示例展示了一个使用特定于模块的接口的存储库(本例中为 JPA):
......@@ -677,7 +677,7 @@ interface UserRepository extends Repository<User, Long> { … }
class User { … }
```
`PersonRepository`引用了`Person`,这是用 JPA `@Entity`注释的,所以这个存储库显然属于 Spring 数据 JPA。`UserRepository`引用`User`,这是用 Spring Data MongoDB 的`@Document`注释的。
`PersonRepository`引用`Person`,这是用 JPA `@Entity`注释的,所以这个存储库显然属于 Spring 数据 JPA。`UserRepository`引用了`User`,这是用 Spring Data MongoDB 的`@Document`注释的。
下面的糟糕示例展示了一个存储库,它使用带有混合注释的域类:
......@@ -723,11 +723,11 @@ class Configuration { … }
以下策略可用于存储库基础结构来解析查询。使用 XML 配置,你可以通过`query-lookup-strategy`属性在名称空间配置策略。对于 Java 配置,可以使用`Enable${store}Repositories`注释的`queryLookupStrategy`属性。某些策略可能不支持特定的数据存储。
* `CREATE`尝试从查询方法名构造特定于存储的查询。一般的方法是从方法名称中删除一组已知的前缀,并解析方法的其余部分。你可以在“[Query Creation](#repositories.query-methods.query-creation)”中阅读有关查询构造的更多信息。
* `CREATE`尝试从查询方法名构造特定于存储的查询。一般的方法是从方法名称中删除一组已知的前缀,并解析方法的其余部分。你可以在“[查询创建](#repositories.query-methods.query-creation)”中阅读有关查询构造的更多信息。
* `USE_DECLARED_QUERY`尝试查找已声明的查询,如果找不到异常,则抛出异常。查询可以通过某个地方的注释来定义,也可以通过其他方式进行声明。请参阅特定存储的文档,以查找该存储的可用选项。如果存储库基础结构在引导过程中未找到该方法的已声明查询,则该查询将失败。
* `USE_DECLARED_QUERY`尝试查找已声明的查询,如果找不到异常,则抛出异常。查询可以通过某个地方的注释来定义,也可以通过其他方式进行声明。请参阅特定存储的文档,以查找该存储的可用选项。如果存储库基础结构在引导阶段没有找到该方法的已声明查询,那么它将失败。
* `CREATE_IF_NOT_FOUND`(默认)组合`CREATE`和`USE_DECLARED_QUERY`。它首先查找已声明的查询,如果没有找到已声明的查询,则创建一个基于名称的自定义方法查询。这是默认的查找策略,因此,如果你没有显式地配置任何内容,就会使用该策略。它允许通过方法名快速定义查询,也可以根据需要引入声明的查询,从而对这些查询进行自定义优化。
* `CREATE_IF_NOT_FOUND`(默认值)结合了`CREATE``USE_DECLARED_QUERY`。它首先查找已声明的查询,如果没有找到已声明的查询,则创建一个基于名称的自定义方法查询。这是默认的查找策略,因此,如果你没有显式地配置任何内容,就会使用该策略。它允许通过方法名快速定义查询,也可以根据需要引入声明的查询,从而对这些查询进行自定义优化。
#### 4.4.2.查询创建
......@@ -757,9 +757,9 @@ interface PersonRepository extends Repository<Person, Long> {
}
```
解析查询方法名分为主语和谓语。第一部分(“find…by”,`exists…By`)定义了查询的主题,第二部分形成了谓词。引入子句(主语)可以包含更多的表达形式。在`find`(或其他介绍关键字)和`By`之间的任何文本都被认为是描述性的,除非使用结果限制关键字之一,例如`Distinct`在要创建的查询或[“top”/“first”限制查询结果](#repositories.limit-query-result)上设置一个不同的标志
解析查询方法名分为主语和谓语。第一部分(`find…By``exists…By`)定义了查询的主题,第二部分形成了谓词。引入子句(主语)可以包含更多的表达形式。在`find`(或其他引入关键字)和`By`之间的任何文本都被认为是描述性的,除非使用结果限制关键字之一,例如`Distinct`在要创建的查询上设置一个不同的标志或[`Top`/`First`限制查询结果]
附录包含[查询方法主题关键字的完整列表](#appendix.query.method.subject)和[查询方法包括排序和大小写修饰符的谓词关键字](#appendix.query.method.predicate)。但是,第一个`By`充当分隔符,指示实际条件谓词的开始。在非常基本的级别上,你可以定义实体属性的条件,并将它们与`And`和`Or`连接起来。
附录包含[查询方法主题关键字的完整列表](#appendix.query.method.subject)[查询方法包括排序和大小写修饰符的谓词关键字](#appendix.query.method.predicate)。但是,第一个`By`充当分隔符,指示实际条件谓词的开始。在非常基本的级别上,你可以定义实体属性的条件,并将它们与`And``Or`连接起来。
解析该方法的实际结果取决于为其创建查询的持久性存储。然而,有一些一般性的事情需要注意:
......@@ -767,7 +767,7 @@ interface PersonRepository extends Repository<Person, Long> {
* 方法解析器支持为单个属性(例如,`findByLastnameIgnoreCase(…)`)或支持忽略 case 的类型的所有属性(通常是`String`实例——例如,`findByLastnameAndFirstnameAllIgnoreCase(…)`)设置`IgnoreCase`标志。是否支持忽略情况可能会因存储而异,因此请参阅引用文档中的相关部分以获取特定于存储的查询方法。
* 可以通过在引用属性的查询方法中附加`OrderBy`子句并提供排序方向(`ASC’`Desc`)来应用静态排序。要创建支持动态排序的查询方法,请参见“[特殊参数处理](#repositories.special-parameters)”。
* 你可以通过在引用属性的查询方法中附加`OrderBy`子句并提供排序方向(`Asc``Desc`)来应用静态排序。要创建支持动态排序的查询方法,请参见“[特殊参数处理](#repositories.special-parameters)”。
#### 4.4.3.属性表达式
......@@ -777,7 +777,7 @@ interface PersonRepository extends Repository<Person, Long> {
List<Person> findByAddressZipCode(ZipCode zipCode);
```
假设 a`Person`具有`Address``ZipCode`。在这种情况下,该方法将创建`x.address.zipCode`属性遍历。解析算法首先将整个部分(“addresszipcode”)解释为属性,然后检查域类中是否有该名称的属性(未大写)。如果算法成功,它将使用该属性。如果不是这样,算法就会将源从右侧的驼峰部分分割为头部和尾部,并尝试找到相应的属性——在我们的示例中,`AddressZip``Code`。如果算法找到了一个带有头部的属性,它就会获取尾部,并继续从那里构建树,按照刚才描述的方式将尾部分割开来。如果第一次分割不匹配,则算法将分割点向左移动(“address”`ZipCode`)并继续。
假设 a`Person`具有`Address``ZipCode`。在这种情况下,该方法创建`x.address.zipCode`属性遍历。解析算法首先将整个部分(`AddressZipCode`)解释为属性,然后检查域类中是否有该名称的属性(未大写)。如果算法成功,它将使用该属性。如果不是这样,则算法将右侧驼峰部分的源拆分为头部和尾部,并尝试找到相应的属性——在我们的示例中,`AddressZip``Code`。如果算法找到了一个带有头部的属性,它就会获取尾部,并继续从那里构建树,按照刚才描述的方式将尾部分割开来。如果第一次分割不匹配,则算法将分割点向左移动(`Address``ZipCode`)并继续。
尽管这在大多数情况下都适用,但算法可能会选择错误的属性。假设`Person`类也有一个`addressZip`属性。该算法将在第一轮分割中匹配,选择错误的属性,并失败(因为`addressZip`的类型可能没有`code`属性)。
......@@ -805,14 +805,14 @@ List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);
```
| |获取`Sort``Pageable`的 API 期望将非 `null’值传递到方法中。<br/>如果不想应用任何排序或分页,请使用`Sort.unsorted()`和`Pageable.unpaged()`。|
| |获取`Sort``Pageable`的 API 期望将非`null`值传递到方法中。<br/>如果不想应用任何排序或分页,请使用`Sort.unsorted()``Pageable.unpaged()`。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
第一个方法允许你将`org.springframework.data.domain.Pageable`实例传递给查询方法,以动态地将分页添加到静态定义的查询中。a`Page`知道可用的元素和页面的总数。它通过触发 Count 查询来计算总数量的基础设施来实现这一点。因为这可能很昂贵(取决于使用的存储空间),所以你可以返回`Slice`。a`Slice`只知道 next`Slice`是否可用,当遍历更大的结果集时,这可能就足够了。
排序选项也通过`Pageable`实例处理。如果只需要排序,请向方法中添加`org.springframework.data.domain.Sort`参数。正如你所看到的,返回`List`也是可能的。在这种情况下,不会创建构建实际`Page`实例所需的附加元数据(这反过来意味着不会发出本来需要的附加计数查询)。相反,它将查询限制为仅查找给定的实体范围。
| |要找出整个查询有多少页,你必须触发一个额外的 Count 查询。<br/>默认情况下,该查询是从你实际触发的查询派生出来的。|
| |要找出整个查询有多少页,你必须触发一个额外的计数查询。<br/>默认情况下,该查询是从你实际触发的查询派生出来的。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
##### 分页和排序
......@@ -873,7 +873,7 @@ List<User> findTop10ByLastname(String lastname, Pageable pageable);
如果将分页或切片应用于限制性查询分页(以及可用页数的计算),则将在有限的结果中应用该分页。
| |通过使用`Sort`参数将结果与动态排序结合起来进行限制,这样就可以表达最小的“k”和最大的“k”元素的查询方法。|
| |通过使用`Sort`参数将结果与动态排序结合起来进行限制,这样就可以表示最小的“k”元素和最大的“k”元素的查询方法。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
#### 4.4.6.返回集合或迭代的存储库方法
......@@ -882,7 +882,7 @@ List<User> findTop10ByLastname(String lastname, Pageable pageable);
##### 使用 streamable 作为查询方法返回类型
你可以使用`Streamable`作为`Iterable`或任何集合类型的替代。它提供了方便的方法来访问非并行的`Stream`(从`Iterable`中缺少)和能够直接`….filter(…)`和`….map(…)`的元素,并将`Streamable`连接到其他元素:
你可以使用`Streamable`作为`Iterable`或任何集合类型的替代。它提供了方便的方法来访问非并行的`Stream`(从`Iterable`缺少)和直接`….filter(…)``….map(…)`上的元素并将`Streamable`连接到其他元素:
例 21。使用 streamable 组合查询方法的结果
......@@ -950,11 +950,11 @@ interface ProductRepository implements Repository<Product, Long> {
|`io.vavr.collection.Set`|`io.vavr.collection.LinkedHashSet`| `java.util.Iterable` |
|`io.vavr.collection.Map`|`io.vavr.collection.LinkedHashMap`| `java.util.Map` |
你可以使用第一列中的类型(或其子类型)作为查询方法返回类型,并获取第二列中的类型作为实现类型,这取决于实际查询结果的 Java 类型(第三列)。或者,你可以声明`Traversable`(VAVR`Iterable`等价值),然后我们从实际的返回值派生实现类。即 a`java.util.List`变成 vAVR`List`或`Seq`,a`java.util.Set`变成 vAVR`LinkedHashSet``Set`,以此类推。
你可以使用第一列中的类型(或其子类型)作为查询方法返回类型,并获取第二列中的类型作为实现类型,这取决于实际查询结果的 Java 类型(第三列)。或者,你可以声明`Traversable`(VAVR`Iterable`等价的),然后我们从实际的返回值派生实现类。即把 a`java.util.List`变成 vAVR`List``Seq`,a`java.util.Set`变成 vAVR`LinkedHashSet``Set`,以此类推。
#### 4.4.7.存储库方法的空处理
在 Spring Data2.0 中,返回单个聚合实例的 Repository增删改查方法使用 Java8 的`Optional`来指示潜在的值不存在。除此之外, Spring Data 支持在查询方法上返回以下包装器类型:
在 Spring Data2.0 中,返回单个聚合实例的存储库增删改查方法使用 Java8 的`Optional`来指示潜在的值缺失。此外, Spring Data 支持在查询方法上返回以下包装器类型:
* `com.google.common.base.Optional`
......@@ -962,17 +962,17 @@ interface ProductRepository implements Repository<Product, Long> {
* `io.vavr.control.Option`
或者,查询方法可以选择完全不使用包装器类型。然后通过返回`null`来表示没有查询结果。返回集合、集合替代方案、包装器和流的存储库方法保证永远不返回`null`,而是返回相应的空表示。有关详细信息,请参见“[存储库查询返回类型](#repository-query-return-types)”。
或者,查询方法可以选择完全不使用包装器类型。然后通过返回`null`来表示没有查询结果。返回集合、集合替代方案、包装器和流的存储库方法保证永远不返回`null`,而是返回相应的空表示。见“[存储库查询返回类型](#repository-query-return-types)”。
##### 可否定性注释
你可以通过使用[Spring Framework’s nullability annotations](https://docs.spring.io/spring-framework/docs/5.3.16/reference/html/core.html#null-safety)来表示存储库方法的可否定性约束。它们提供了一种工具友好的方法和 OPT-在运行时进行`null`检查,如下所示:
* [`@NonNullApi`](https://docs.spring.io/spring/docs/5.3.16/javadoc-api/org/springframework/lang/NonNullApi.html):在包级别上用于声明参数和返回值的默认行为分别是既不接受也不产生`null`值。
* [`@NonNullApi`](https://DOCS. Spring.io/ Spring/DOCS/5.3.16/javadoc-api/org/springframework/lang/nonnullapi.html):在包级别上用于声明参数和返回值的默认行为分别是既不接受也不产生`null`值。
* [`@NonNull`](https://docs.spring.io/spring/docs/5.3.16/javadoc-api/org/springframework/lang/NonNull.html):用于参数或返回值,该参数或返回值必须不是`null`(在适用`@NonNullApi`的参数和返回值上不需要)。
* [`@NonNull`](https://DOCS. Spring.io/ Spring/DOCS/5.3.16/javadoc-api/org/springframework/lang/nonnull.html):用于参数或返回值,该参数或返回值必须不是`null`(对于`@NonNullApi`适用的参数和返回值不需要)。
* [`@Nullable`](https://docs.spring.io/spring/docs/5.3.16/javadoc-api/org/springframework/lang/Nullable.html):用于可以是`null`的参数或返回值。
* [`@Nullable`](https://DOCS. Spring.io/ Spring/DOCS/5.3.16/javadoc-api/org/springframework/lang/nullable.html):用于可以是`null`的参数或返回值。
Spring 注释是用[JSR 305](https://jcp.org/en/jsr/detail?id=305)注释(一种休眠但广泛使用的 JSR)进行元注释的。JSR305 元注释允许工具供应商(例如[IDEA](https://www.jetbrains.com/help/idea/nullable-and-notnull-annotations.html)[Eclipse](https://help.eclipse.org/oxygen/index.jsp?topic=/org.eclipse.jdt.doc.user/tasks/task-using_external_null_annotations.htm)[Kotlin](https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types))以通用方式提供空安全支持,而无需对 Spring 注释进行硬编码支持。要为查询方法启用可否定性约束的运行时检查,你需要在包级别上通过在`package-info.java`中使用 Spring 的`@NonNullApi`来激活非可否定性,如以下示例所示:
......@@ -983,7 +983,7 @@ Spring 注释是用[JSR 305](https://jcp.org/en/jsr/detail?id=305)注释(一
package com.acme;
```
一旦非空默认值到位,存储库查询方法调用将在运行时针对无效约束进行验证。如果查询结果违反了定义的约束,将引发异常。当该方法返回`null`但被声明为不可空(默认情况下,在存储库所在的包上定义了注释)时,就会发生这种情况。如果你希望再次 OPT 到无效的结果,可以在单个方法上选择性地使用`@Nullable`。使用本节开头提到的结果包装器类型将继续按预期工作:将空结果转换为表示缺省的值。
一旦非空默认值到位,存储库查询方法调用将在运行时针对无效约束进行验证。如果查询结果违反了定义的约束,将引发异常。当方法返回`null`但被声明为 non-nullable 时,就会发生这种情况(缺省情况,在存储库所在的包上定义了注释)。如果你希望再次 OPT 到无效的结果,可以在单个方法上选择性地使用`@Nullable`。使用本节开头提到的结果包装器类型将继续按预期工作:将空结果转换为表示缺省的值。
下面的示例展示了刚才描述的一些技术:
......@@ -1009,11 +1009,11 @@ interface UserRepository extends Repository<User, Long> {
|-----|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|当查询不产生结果时抛出`EmptyResultDataAccessException`。当将`emailAddress`传递给方法的`null`时抛出`IllegalArgumentException`。|
|**3**|当查询不产生结果时,返回`null`<br/>还接受`null`作为`emailAddress`的值。|
|**4**|当查询不产生结果时,返回`Optional.empty()`。<br/>当将`emailAddress`传递给方法的值`IllegalArgumentException`时,抛出一个`IllegalArgumentException`。|
|**4**|当查询不产生结果时返回`Optional.empty()`。当将`emailAddress`传递给方法的`null`时,抛出一个`IllegalArgumentException`。|
##### 基于 Kotlin 的存储库中的可否定性
Kotlin 已将[可否定性约束](https://kotlinlang.org/docs/reference/null-safety.html)的定义烘焙到语言中。 Kotlin 代码编译成字节码,其不通过方法签名而是通过编译元数据来表示可否定性约束。确保在你的项目中包含`kotlin-reflect` jar,以实现对 Kotlin 的无效约束的内省。 Spring 数据存储库使用语言机制来定义那些约束,以应用相同的运行时检查,如下所示:
Kotlin 已将[可否定性约束](https://kotlinlang.org/docs/reference/null-safety.html)的定义烘焙到语言中。 Kotlin 代码编译成字节码,其不通过方法签名而是通过编译元数据来表示可否定性约束。确保在你的项目中包含`kotlin-reflect` jar,以便能够对 Kotlin 的无效约束进行内省。 Spring 数据存储库使用语言机制来定义那些约束,以应用相同的运行时检查,如下所示:
例 24。在 Kotlin 存储库上使用可否定性约束
......@@ -1057,7 +1057,7 @@ try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
}
```
| |并非所有 Spring 数据模块前都支持`Stream<T>`作为返回类型。|
| |并非所有 Spring 数据模块前都支持`Stream<T>`作为返回类型。|
|---|---------------------------------------------------------------------------|
#### 4.4.9.异步查询结果
......@@ -1082,11 +1082,11 @@ ListenableFuture<User> findOneByLastname(String lastname); (3)
### 4.5.创建存储库实例
本节介绍如何为已定义的存储库接口创建实例和 Bean 定义。这样做的一种方法是使用与每个支持存储库机制的 Spring 数据模块一起提供的 Spring 名称空间,尽管我们通常建议使用 Java 配置。
本节介绍如何为已定义的存储库接口创建实例和 Bean 定义。这样做的一种方法是使用每个支持存储库机制的 Spring 数据模块附带的 Spring 名称空间,尽管我们通常建议使用 Java 配置。
#### 4.5.1.XML 配置
Spring 每个数据模块包括一个`repositories`元素,该元素允许你定义一个基包, Spring 可以为你扫描该基包,如以下示例所示:
Spring 每个数据模块包括一个`repositories`元素,该元素允许你定义一个基包,由 Spring 为你扫描,如以下示例所示:
例 27。通过 XML 启用 Spring 数据存储库
......@@ -1109,7 +1109,7 @@ Spring 每个数据模块包括一个`repositories`元素,该元素允许你
##### 使用过滤器
默认情况下,基础结构会获取扩展位于配置的基包下的特定于持久性技术的`Repository`子接口的每个接口,并为其创建一个 Bean 实例。然而,你可能想要更细粒度的控制,来控制哪些接口为它们创建了 Bean 实例。为此,在`<repositories />`元素中使用`<include-filter />`和`<exclude-filter />`元素。语义与 Spring 上下文名称空间中的元素完全等价。有关这些元素的详细信息,请参见[Spring reference documentation](https://docs.spring.io/spring-framework/docs/5.3.16/reference/html/core.html#beans-scanning-filters)。
默认情况下,基础设施会获取扩展位于配置的基包下的特定于持久性技术的`Repository`子接口的每个接口,并为其创建一个 Bean 实例。然而,你可能希望对哪些接口为它们创建了 Bean 实例进行更细粒度的控制。为此,在`<repositories />`元素中使用`<include-filter />``<exclude-filter />`元素。语义与 Spring 上下文名称空间中的元素完全等价。有关这些元素的详细信息,请参见[Spring reference documentation](https://docs.spring.io/spring-framework/docs/5.3.16/reference/html/core.html#beans-scanning-filters)
例如,为了将某些接口从作为存储库 bean 的实例化中排除,你可以使用以下配置:
......@@ -1143,12 +1143,12 @@ class ApplicationConfiguration {
}
```
| |前面的示例使用了 JPA 特定的注释,你将根据实际使用的存储模块对其进行更改。这同样适用于`EntityManagerFactory` Bean 的定义。请参阅涵盖特定于商店的配置的部分。|
| |前面的示例使用特定于 JPA 的注释,你将根据实际使用的存储模块对其进行更改。这同样适用于`EntityManagerFactory` Bean 的定义。请参阅涵盖特定于商店的配置的部分。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
#### 4.5.3.独立使用
你还可以在 Spring 容器之外使用存储库基础设施——例如,在 CDI 环境中。在你的 Classpath 中仍然需要一些 Spring 库,但是,通常情况下,你也可以通过编程的方式设置存储库。 Spring 提供存储库支持的数据模块带有你可以使用的持久性技术特定的`RepositoryFactory`,如下所示:
你还可以在 Spring 容器之外使用存储库基础设施——例如,在 CDI 环境中。在你的 Classpath 中仍然需要一些 Spring 库,但是,通常情况下,你也可以通过编程的方式设置存储库。 Spring 提供存储库支持的数据模块附带你可以使用的持久性技术特有`RepositoryFactory`,如下所示:
例 30。仓库工厂的独立使用
......@@ -1202,7 +1202,7 @@ interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepos
使用存储库接口扩展片段接口结合了增删改查和自定义功能,并使其对客户可用。
Spring 数据存储库是通过使用形成存储库组合的片段来实现的。片段是基本存储库、功能方面(如[QueryDsl](#core.extensions.querydsl))和自定义接口及其实现。每次向存储库接口添加一个接口时,都会通过添加一个片段来增强组合。基础存储库和存储库方面的实现由每个 Spring 数据模块提供
Spring 数据存储库是通过使用形成存储库组合的片段来实现的。片段是基本存储库、功能方面(如[QueryDsl](#core.extensions.querydsl))和自定义接口及其实现。每次向存储库接口添加一个接口时,都会通过添加一个片段来增强组合。基础存储库和存储库方面的实现是由每个 Spring 数据模块提供的
下面的示例展示了自定义接口及其实现:
......@@ -1250,7 +1250,7 @@ interface UserRepository extends CrudRepository<User, Long>, HumanRepository, Co
}
```
存储库可以由多个自定义实现组成,这些实现是按照其声明的顺序导入的。自定义实现比基本实现和存储库方面具有更高的优先级。这种排序使你可以重写基本存储库和方面方法,并且如果两个片段提供相同的方法签名,则可以解决歧义。存储库片段不限于在单个存储库接口中使用。多个存储库可能使用一个片段接口,允许你在不同的存储库重用定制。
存储库可以由多个自定义实现组成,这些实现是按照其声明的顺序导入的。自定义实现比基本实现和存储库方面具有更高的优先级。这种排序使你可以重写基本存储库和方面方法,并且如果两个片段提供相同的方法签名,则可以解决歧义。存储库片段不限于在单个存储库接口中使用。多个存储库可能使用一个片段接口,允许你在不同的存储库之间重用定制。
下面的示例展示了一个存储库片段及其实现:
......@@ -1283,7 +1283,7 @@ interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<
##### 配置
如果你使用名称空间配置,存储库基础设施将通过扫描它在其中找到存储库的包下面的类来尝试自动检测自定义实现片段。这些类需要遵循将命名空间元素的`repository-impl-postfix`属性追加到片段接口名称的命名惯例。此后缀缺省为`Impl`。下面的示例展示了一个使用默认后缀的存储库和一个为后缀设置自定义值的存储库:
如果你使用名称空间配置,存储库基础设施将通过扫描其发现存储库的包下面的类,尝试自动检测自定义实现片段。这些类需要遵循将命名空间元素的`repository-impl-postfix`属性追加到片段接口名称的命名惯例。此后缀缺省为`Impl`。下面的示例展示了一个使用默认后缀的存储库和一个为后缀设置自定义值的存储库:
例 38。配置示例
......@@ -1297,9 +1297,9 @@ interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<
###### 歧义的解决
如果在不同的包中发现了具有匹配的类名的多个实现,则 Spring Data 使用 Bean 名称来标识要使用哪个。
如果在不同的包中发现了具有匹配的类名的多个实现,则 Spring 数据使用 Bean 名称来标识要使用哪个。
给出了下面两个用于`CustomizedUserRepository`的自定义实现,使用了第一个实现。 Bean 它的名称是`customizedUserRepositoryImpl`,它与片段接口加上后缀`Impl`相匹配。
给出了下面两个用于`CustomizedUserRepository`的自定义实现,使用了第一个实现。 Bean 它的名称是`customizedUserRepositoryImpl`,它与片段接口的名称(`CustomizedUserRepository`加上后缀`Impl`相匹配。
例 39。解决模棱两可的实现
......@@ -1322,11 +1322,11 @@ class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
}
```
如果用`@Component("specialCustom")`对`UserRepository`接口进行注释,则 Bean 名称加上`Impl`,然后与`com.acme.impl.two`中为存储库实现定义的名称匹配,并使用它来代替第一个。
如果用`@Component("specialCustom")`注释`UserRepository`接口,则 Bean 名称加上`Impl`,然后与`com.acme.impl.two`中为存储库实现定义的名称匹配,并使用它来代替第一个。
###### 手动接线
如果你的自定义实现仅使用基于注释的配置和自动布线,则前面所示的方法工作得很好,因为它被视为任何其他方法 Spring Bean。如果你的实现片段 Bean 需要特殊的接线,则可以声明 Bean 并根据[前一节](#repositories.single-repository-behaviour.ambiguity)中描述的约定对其进行命名。然后,基础设施通过名称引用手动定义的 Bean 定义,而不是创建本身。下面的示例展示了如何手动连接自定义实现:
Spring Bean Bean 如果你的自定义实现仅使用基于注释的配置和自动布线,则前面所示的方法工作得很好,因为它被视为任何其他方法。如果你的实现片段 Bean 需要特殊的接线,则可以声明 Bean 并根据[前一节](#repositories.single-repository-behaviour.ambiguity)中描述的约定对其进行命名。然后,基础设施通过名称引用手动定义的 Bean 定义,而不是创建本身。下面的示例展示了如何手动连接自定义实现:
例 40。自定义实现的手动接线
......@@ -1368,7 +1368,7 @@ class MyRepositoryImpl<T, ID>
| |该类需要具有存储特定的存储库工厂实现所使用的超类的构造函数。<br/>如果存储库基类具有多个构造函数,则重写一个`EntityInformation`加上一个存储特定的基础设施对象(例如`EntityManager`或模板类)。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
最后一步是使 Spring 数据基础设施了解定制的存储库基类。在 Java 配置中,你可以通过使用`@Enable${store}Repositories`注释的`repositoryBaseClass`属性来实现这一点,如以下示例所示:
最后一步是使 Spring 数据基础设施了解定制的存储库基类。在 Java 配置中,你可以通过使用`@Enable${store}Repositories`注释的`repositoryBaseClass`属性来实现这一点,如例所示:
例 42。使用 JavaConfig 配置自定义存储库基类
......@@ -1412,7 +1412,7 @@ class AnAggregateRoot {
|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|在所有事件都已发布之后,我们有一个用`@AfterDomainEventPublication`注释的方法。<br/>你可以使用它来清除要发布的事件列表(以及其他用途)。|
当 Spring 数据存储库的`save(…)`、`saveAll(…)`、`delete(…)`或`deleteAll(…)`方法被调用时,就会调用这些方法。
次调用 Spring 数据存储库的`save(…)``saveAll(…)``delete(…)``deleteAll(…)`方法之一时,都会调用这些方法。
### 4.8. Spring 数据扩展
......@@ -1467,7 +1467,7 @@ userRepository.findAll(predicate);
#### 4.8.2.网络支持
Spring 支持存储库的数据模块编程模型提供了各种 Web 支持。与 Web 相关的组件要求 Spring MVC 容器在 Classpath 上。其中一些甚至提供了[Spring HATEOAS](https://github.com/spring-projects/spring-hateoas)的集成。通常,通过在 JavaConfig 配置类中使用`@EnableSpringDataWebSupport`注释来启用集成支持,如下例所示:
Spring 支持存储库的数据模块编程模型提供了各种 Web 支持。与 Web 相关的组件需要 Spring MVC JAR 在 Classpath 上。其中一些甚至提供了[Spring HATEOAS](https://github.com/spring-projects/spring-hateoas)的集成。通常,通过在 JavaConfig 配置类中使用`@EnableSpringDataWebSupport`注释来启用集成支持,如下例所示:
例 47。启用 Spring 数据 Web 支持
......@@ -1495,13 +1495,13 @@ class WebConfiguration {}
[上一节](#core.web)中显示的配置记录了一些基本组件:
* a[使用`DomainClassConverter`类](#core.web.basic.domain-class-converter),用于让 Spring MVC 从请求参数或路径变量解析存储库管理的域类的实例。
* [使用`DomainClassConverter`类](#core.web.basic.domain-class-converter)让 Spring MVC 从请求参数或路径变量解析存储库管理的域类实例。
* [HandlerMethodarGumentResolver’](#core.web.basic.paging-and-sorting)实现让 Spring MVC 从请求参数解析`Pageable`和`Sort`实例。
* [`HandlerMethodArgumentResolver`](#core.web.basic.paging-and-sorting)实现让 Spring MVC 从请求参数解析`Pageable``Sort`实例。
* [Jackson Modules](#core.web.basic.jackson-mappers)根据所使用的 Spring 数据模块,对`Point`和`Distance`之类的类型进行反/序列化,或者存储特定的类型
* [Jackson 模块](#core.web.basic.jackson-mappers)以反-/序列化`Point``Distance`之类的类型,或者存储特定的类型,这取决于所使用的 Spring 数据模块
###### Using the `DomainClassConverter` Class
###### 使用`DomainClassConverter`类
`DomainClassConverter`类允许你在 Spring MVC 控制器方法签名中直接使用域类型,这样你就不需要通过存储库手动查找实例,如下例所示:
......@@ -1528,7 +1528,7 @@ class UserController {
###### 用于分页和排序的 HandlerMethodargumentResolver
[上一节](#core.web.basic.domain-class-converter)中显示的配置片段还注册了`PageableHandlerMethodArgumentResolver`以及`SortHandlerMethodArgumentResolver`的实例。注册使`Pageable`和`Sort`成为有效的控制器方法参数,如下例所示:
[上一节](#core.web.basic.domain-class-converter)中显示的配置片段还注册了`PageableHandlerMethodArgumentResolver`以及`SortHandlerMethodArgumentResolver`的实例。注册允许`Pageable``Sort`为有效的控制器方法参数,如下例所示:
例 50。使用 Pageable 作为控制器方法参数
......@@ -1552,12 +1552,12 @@ class UserController {
}
```
Spring MVC 通过使用以下默认配置,尝试从请求参数中派生`Pageable`实例,从而得到前面的方法签名
前面的方法签名会导致 Spring MVC 尝试通过使用以下默认配置从请求参数派生`Pageable`实例
|`page`|要检索的页面。索引为 0,默认值为 0。|
|------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|`size`|要检索的页面大小。默认值为 20。|
|`sort`|Properties that should be sorted by in the format `property,property(,ASC|(desc)(,ignorecase)。默认的排序方向是区分大小写的升序。如果要切换方向或大小写敏感度,请使用多个`sort`参数——例如,`?sort=firstname&sort=lastname,asc&sort=city,ignorecase`。|
|`sort`|Properties that should be sorted by in the format `property,property(,ASC|desc)`. The default sort direction is case-sensitive ascending. Use multiple `sort` parameters if you want to switch direction or case sensitivity — for example, `?sort=firstname&sort=lastname,ASC&sort=city,ignorecase`。|
要定制此行为,请注册一个 Bean,该 Bean 分别实现`PageableHandlerMethodArgumentResolverCustomizer`接口或`SortHandlerMethodArgumentResolverCustomizer`接口。调用它的`customize()`方法,允许你更改设置,如下例所示:
......@@ -1567,7 +1567,7 @@ Spring MVC 通过使用以下默认配置,尝试从请求参数中派生`Pagea
}
```
如果设置现有`MethodArgumentResolver`的属性对你的目的来说是不够的,那么扩展`SpringDataWebConfiguration`或启用 Hateoas 的等效方法,覆盖`pageableResolver()`或`sortResolver()`方法,并导入自定义的配置文件,而不是使用`@Enable`注释。
如果设置现有`MethodArgumentResolver`的属性对你的目的来说是不够的,那么扩展`SpringDataWebConfiguration`或启用 Hateoas 的等效方法,覆盖`pageableResolver()``sortResolver()`方法,并导入自定义的配置文件,而不是使用`@Enable`注释。
如果需要从请求中解析多个`Pageable``Sort`实例(例如,对于多个表),则可以使用 Spring 的`@Qualifier`注释来区分一个实例和另一个实例。然后,请求参数必须以`${qualifier}_`作为前缀。下面的示例展示了生成的方法签名:
......@@ -1579,11 +1579,11 @@ String showUsers(Model model,
你必须填充`thing1_page``thing2_page`,以此类推。
传递到该方法的默认`Pageable`相当于`PageRequest.of(0, 20)`,但是你可以使用`@PageableDefault`参数上的`@PageableDefault`注释来定制它。
传递到该方法的默认`Pageable`相当于`PageRequest.of(0, 20)`,但是你可以使用`@PageableDefault`参数上的`@PageableDefault`注释来定制它。
##### 对页面的超媒体支持
Spring Hateoas 附带一个表示模型类,该表示模型类允许使用必要的`Page`元数据以及链接来丰富`Page`实例的内容,从而使客户端能够轻松地在页面中导航。将`Page`转换为`PagedResources`是通过 Spring Hateoas`ResourceAssembler`接口的实现完成的,该接口称为`PagedResourcesAssembler`。下面的示例展示了如何使用`PagedResourcesAssembler`作为控制器方法参数:
Spring Hateoas 附带一个表示模型类`PagedResources`,该表示模型类允许使用必要的`Page`元数据以及链接来丰富`Page`实例的内容,从而使客户端能够轻松地在页面中导航。将`Page`转换为`PagedResources`是通过 Spring Hateoas`ResourceAssembler`接口的实现完成的,该接口称为`PagedResourcesAssembler`。下面的示例展示了如何使用`PagedResourcesAssembler`作为控制器方法参数:
例 51。使用 PagedResourcesAssembler 作为控制器方法参数
......@@ -1603,7 +1603,7 @@ class PersonController {
}
```
启用配置,如前面的示例所示,让`PagedResourcesAssembler`用作控制器方法参数。在上调用`toResources(…)`具有以下效果:
启用配置,如前面的示例所示,让`PagedResourcesAssembler`用作控制器方法参数。在上调用`toResources(…)`具有以下效果:
* `Page`的内容成为`PagedResources`实例的内容。
......@@ -1611,7 +1611,7 @@ class PersonController {
* 根据页面的状态,`PagedResources`可能会附加`prev``next`链接。链接指向该方法映射到的 URI。添加到该方法中的分页参数与`PageableHandlerMethodArgumentResolver`的设置匹配,以确保以后可以解析链接。
假设我们在数据库中有 30 个`Person`实例。你现在可以触发一个请求(`get[http://localhost:8080/persons](http://localhost:8080/persons)`),并看到类似于以下内容的输出:
假设我们在数据库中有 30 个`Person`实例。你现在可以触发一个请求(`GET [http://localhost:8080/persons](http://localhost:8080/persons)`),并看到类似于以下内容的输出:
```
{ "links" : [ { "rel" : "next",
......@@ -1633,9 +1633,9 @@ class PersonController {
##### Spring 数据 Jackson 模块
核心模块和一些存储特定的模块附带一组用于类型的 Jackson 模块,例如`org.springframework.data.geo.Distance`和`org.springframework.data.geo.Point`,由 Spring 数据域使用。一旦启用[web support](#core.web)并且`com.fasterxml.jackson.databind.ObjectMapper`可用,就会导入这些模块。
核心模块和一些特定的存储模块附带一组用于类型的 Jackson 模块,如`org.springframework.data.geo.Distance``org.springframework.data.geo.Point`,由 Spring 数据域使用。一旦启用[网络支持](#core.web)并且`com.fasterxml.jackson.databind.ObjectMapper`可用,就会导入这些模块。
在初始化`SpringDataJacksonModules`期间,就像`SpringDataJacksonConfiguration`一样,被基础结构拾取,这样声明的`com.fasterxml.jackson.databind.Module`s 可用于 Jackson`ObjectMapper`
在初始化`SpringDataJacksonModules`期间,就像`SpringDataJacksonConfiguration`一样,被基础结构拾取,这样声明的`com.fasterxml.jackson.databind.Module`s 对 Jackson`ObjectMapper`是可用的
公共基础设施注册了用于下列域类型的数据绑定 mixin。
......@@ -1652,7 +1652,7 @@ org.springframework.data.geo.Polygon
##### 网络数据库支持
可以使用 Spring 数据投影(在[预测](#projections)中描述)通过使用[JSONPath](https://goessner.net/articles/JsonPath/)表达式(需要[Jayway JsonPath](https://github.com/json-path/JsonPath)或[XPath](https://www.w3.org/TR/xpath-31/)表达式(需要[XmlBeam](https://xmlbeam.org/))来绑定传入的请求有效负载,如下例所示:
可以使用 Spring 数据投影(在[预测](#projections)中描述)通过使用[JSONPath](https://goessner.net/articles/JsonPath/)表达式(需要[Jayway Jsonpath](https://github.com/json-path/JsonPath)[XPath](https://www.w3.org/TR/xpath-31/)表达式(需要[XmlBeam](https://xmlbeam.org/))来绑定传入的请求有效负载,如下例所示:
例 52。使用 JSONPath 或 XPath 表达式的 HTTP 有效负载绑定
......@@ -1672,15 +1672,15 @@ public interface UserPayload {
你可以使用前面示例中所示的类型作为 Spring MVC 处理程序方法参数,或者在`RestTemplate`的方法之一上使用`ParameterizedTypeReference`。前面的方法声明将尝试在给定的文档中的任何地方找到`firstname``lastname`XML 查找是在传入文档的顶层执行的。它的 JSON 变体首先尝试一个顶级的`lastname`,但如果前者不返回一个值,则还会尝试在`lastname`子文档中嵌套的`user`。这样,在不需要客户端调用公开的方法(通常是基于类的有效负载绑定的一个缺点)的情况下,可以轻松地减轻源文档结构中的更改。
支持[Projections](#projections)中所述的嵌套投影。如果方法返回复杂的非接口类型,则使用 Jackson`ObjectMapper`映射最终值。
支持[预测](#projections)中所述的嵌套投影。如果方法返回复杂的非接口类型,则使用 Jackson`ObjectMapper`映射最终值。
对于 Spring MVC,一旦处于活动状态并且所需的依赖关系在 Classpath 上可用,所需的转换器就被自动注册。要使用`RestTemplate`,请手动注册`ProjectingJackson2HttpMessageConverter`或`XmlBeamHttpMessageConverter`。
对于 Spring MVC,一旦处于活动状态并且所需的依赖关系在 Classpath 上可用,则所需的转换器被自动注册。要使用`RestTemplate`,请手动注册一个`ProjectingJackson2HttpMessageConverter``XmlBeamHttpMessageConverter`
有关更多信息,请参见规范[Spring Data Examples repository](https://github.com/spring-projects/spring-data-examples)中的[Web 投影示例](https://github.com/spring-projects/spring-data-examples/tree/master/web/projection)
##### QueryDSL Web 支持
对于那些具有[QueryDSL](http://www.querydsl.com/)集成的存储,可以从`Request`查询字符串中包含的属性派生查询。
对于那些具有[QueryDSL](http://www.querydsl.com/)集成的存储,可以从`Request`查询字符串中包含的属性派生查询。
考虑以下查询字符串:
......@@ -1697,9 +1697,9 @@ QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))
| |当在 Classpath 上找到 QueryDSL 时,该功能将与`@EnableSpringDataWebSupport`一起自动启用。|
|---|------------------------------------------------------------------------------------------------------------------------|
将`@QuerydslPredicate`添加到方法签名中,可以提供一个现成的`Predicate`,你可以使用`QuerydslPredicateExecutor`来运行它。
`@QuerydslPredicate`添加到方法签名中,提供一个现成的`Predicate`,你可以使用`QuerydslPredicateExecutor`来运行它。
| |类型信息通常是从方法的返回类型解析出来的。<br/>由于该信息不一定与域类型匹配,因此使用`root`的`QuerydslPredicate`属性可能是个好主意。|
| |类型信息通常是从方法的返回类型解析的。<br/>由于该信息不一定与域类型匹配,因此使用`root``QuerydslPredicate`属性可能是个好主意。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
下面的示例展示了如何在方法签名中使用`@QuerydslPredicate`:
......@@ -1726,11 +1726,11 @@ class UserController {
默认绑定如下:
* 在简单属性上`Object`为`eq`。
* `Object`在简单属性上`eq`
* `Object`在集合 like 属性上为`contains`
* `Collection`在简单属性上为`in`。
* 在简单属性上`Collection``in`
你可以通过`@QuerydslPredicate``bindings`属性或通过使用 Java8`default methods`并将`QuerydslBinderCustomizer`方法添加到存储库接口来定制这些绑定,如下所示:
......@@ -1757,7 +1757,7 @@ interface UserRepository extends CrudRepository<User, String>,
|**4**|将`String`属性的默认绑定定义为不区分大小写的`contains`匹配。|
|**5**|将`password`属性从`Predicate`分辨率中排除。|
| |你可以注册一个`QuerydslBinderCustomizerDefaults` Bean,保存默认的 QueryDSL 绑定,然后再从存储库应用特定的绑定,或者`@QuerydslPredicate`。|
| |在从存储库应用特定绑定之前,可以注册一个持有默认 QueryDSL 绑定的`QuerydslBinderCustomizerDefaults` Bean 或`@QuerydslPredicate`。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
#### 4.8.3.存储库填充器
......@@ -1825,7 +1825,7 @@ interface UserRepository extends CrudRepository<User, String>,
</beans>
```
## 5. Projections
## 5. 预测
Spring 数据查询方法通常返回由存储库管理的聚合根的一个或多个实例。然而,有时基于这些类型的某些属性创建投影可能是可取的。 Spring 数据允许建模专用的返回类型,以更有选择性地检索托管聚合的部分视图。
......@@ -1972,7 +1972,7 @@ interface NamesOnly {
}
```
注意 SPEL 表达式是如何引用`myBean`并调用`getFullName(…)`方法并将投影目标作为方法参数转发的。由 SPEL 表达式评估支持的方法也可以使用方法参数,然后可以从表达式引用这些参数。该方法参数可通过名为`Object`的`args`的数组获得。下面的示例展示了如何从`args`数组中获取方法参数:
注意 SPEL 表达式是如何引用`myBean`并调用`getFullName(…)`方法并将投影目标作为方法参数转发的。由 SPEL 表达式评估支持的方法也可以使用方法参数,然后可以从表达式引用这些参数。该方法参数可通过名为`Object``args`的数组获得。下面的示例展示了如何从`args`数组中获取方法参数:
例 64。样本人物对象
......@@ -1988,7 +1988,7 @@ interface NamesOnly {
#### 5.1.3.可空包装纸
投影接口中的吸取器可以利用可空包装器来提高零值安全性。当前支持的包装器类型如下:
投影接口中的吸取器可以使用可空包装器来提高零安全性。当前支持的包装器类型如下:
* `java.util.Optional`
......@@ -2042,7 +2042,7 @@ class NamesOnly {
}
```
| |避免使用投影 DTO 的样板代码<br/><br/>通过使用[Project Lombok](https://projectlombok.org),可以极大地简化 DTO 的代码,它提供了`@Value`注释(不要与 Spring 的`@Value`前面的接口示例中显示的注释相混淆)。<br/>如果使用 Project Lombok 的`@Value`注释,前面显示的示例 DTO 将变成如下:<br/><br/>``gt@value<<br/>class namesonly=”698"/>LastName;<br/>}<br/>```<br/>缺省情况下,<br/>字段是`private final`,该类公开了一个构造函数,该构造函数接受所有字段并自动获得`equals(…)`和`hashCode()`实现的方法。|
| |避免使用投影 DTO 的样板代码<br/><br/>使用[龙目岛计划](https://projectlombok.org)可以极大地简化 DTO 的代码,它提供了`@Value`注释(不要与 Spring 的`@Value`前面的接口示例中显示的注释混淆)。<br/>如果使用 Project Lombok 的`@Value`注释,前面显示的示例 DTO 将变成如下:<br/><br/>缺省情况下,该类公开了一个构造函数,该构造函数接受所有字段并自动实现`equals(…)``hashCode()`方法。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
### 5.3.动态投影
......@@ -2058,7 +2058,7 @@ interface PersonRepository extends Repository<Person, UUID> {
}
```
通过这种方式,可以使用该方法来获得如当前所应用的或具有投影的聚合体,如以下示例所示:
通过这种方式,可以使用该方法获得所述聚集如当前所应用的或与所应用的投影,如以下示例所示:
例 68。使用具有动态投影的存储库
......@@ -2092,13 +2092,13 @@ void someMethod(PersonRepository people) {
* `ExampleMatcher`:`ExampleMatcher`包含有关如何匹配特定字段的详细信息。它可以在多个示例中重用。
* `Example`:an`Example`由探针和`ExampleMatcher`组成。它用于创建查询。
* `Example`:一个`Example`由探针和`ExampleMatcher`组成。它用于创建查询。
示例查询非常适合于以下几种用例:
* 使用一组静态或动态约束来查询你的数据存储。
* 频繁地重构域对象,而不必担心破坏现有的查询。
* 经常重构域对象,而不必担心破坏现有的查询。
* 独立于底层数据存储 API 工作。
......@@ -2108,7 +2108,7 @@ void someMethod(PersonRepository people) {
* 只支持字符串的开始/包含/结束/正则表达式匹配,以及其他属性类型的精确匹配。
在开始使用示例查询之前,你需要有一个域对象。要开始,请为你的存储库创建一个接口,如以下示例所示:
在开始使用示例查询之前,你需要有一个域对象。要开始,请为存储库创建一个接口,如以下示例所示:
例 69。样本人物对象
......@@ -2127,10 +2127,10 @@ public class Person {
前面的示例展示了一个简单的域对象。你可以使用它来创建`Example`。默认情况下,具有`null`值的字段将被忽略,字符串将通过使用特定于存储的默认值进行匹配。
| |根据示例条件将属性包含到查询中是基于可否定性的。除非[忽略属性路径](#query-by-example.matchers),否则始终包括使用基元类型(`INT’,`double`,…)的属性。|
| |根据示例条件将属性包含到查询中是基于可否定性的。使用原语类型(`int``double`,…)的属性总是包括在内,除非[忽略属性路径](#query-by-example.matchers)。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
可以通过使用`of`工厂方法或使用[`examplematcher’](#query-by-example.matchers)构建示例。`Example`是不变的。下面的清单展示了一个简单的示例:
可以使用`of`工厂方法或[`ExampleMatcher`](#query-by-example.matchers)构建示例。`Example`是不变的。下面的清单展示了一个简单的示例:
例 70。简单的例子
......@@ -2188,7 +2188,7 @@ Example<Person> example = Example.of(person, matcher); (7)
|**6**|构造一个新的`ExampleMatcher`以忽略`lastname`属性路径,包括空值,并执行后缀字符串匹配。|
|**7**|基于域对象和配置的`ExampleMatcher`创建一个新的`Example`。|
默认情况下,`ExampleMatcher`期望探测上设置的所有值都匹配。如果希望获得与隐式定义的任何谓词匹配的结果,请使用`ExampleMatcher.matchingAny()`。
默认情况下,`ExampleMatcher`期望探针上设置的所有值都匹配。如果希望得到与隐式定义的任何谓词匹配的结果,请使用`ExampleMatcher.matchingAny()`
你可以为各个属性指定行为(例如“firstname”和“lastname”,或者,对于嵌套属性,“address.city”)。你可以使用匹配的选项和大小写敏感性来调整它,如以下示例所示:
......@@ -2228,7 +2228,7 @@ ExampleMatcher matcher = ExampleMatcher.matching()
Spring 数据提供了复杂的支持,以透明地跟踪谁创建或更改了一个实体以及何时发生了更改。为了从该功能中受益,你必须为你的实体类配备审计元数据,这些元数据可以使用注释或通过实现接口来定义。此外,必须通过注释配置或 XML 配置来启用审计,以注册所需的基础设施组件。有关配置示例,请参阅特定于商店的部分。
| |只跟踪创建和修改日期的应用程序不需要指定[`AuditorAware`](#auditing.auditor-aware)。|
| |只跟踪创建和修改日期的应用程序不需要指定[`AuditorAware`]。|
|---|---------------------------------------------------------------------------------------------------------------------------------|
#### 7.1.1.基于注释的审计元数据
......@@ -2281,7 +2281,7 @@ class AuditMetadata {
#### 7.1.3.`AuditorAware`
在使用`@CreatedBy`或`@LastModifiedBy`的情况下,审计基础结构需要以某种方式意识到当前的主体。为了做到这一点,我们提供了一个`AuditorAware<T>`SPI 接口,你必须实现该接口,以告知基础设施当前与应用程序交互的用户或系统是谁。泛型类型`T`定义了用`@CreatedBy`或`@LastModifiedBy`注释的属性必须是什么类型。
在使用`@CreatedBy``@LastModifiedBy`的情况下,审计基础结构需要以某种方式意识到当前的主体。为了做到这一点,我们提供了一个`AuditorAware<T>`SPI 接口,你必须实现该接口,以告知基础结构当前与应用程序交互的用户或系统是谁。泛型类型`T`定义了用`@CreatedBy``@LastModifiedBy`注释的属性必须是什么类型。
下面的示例展示了使用 Spring Security 的`Authentication`对象的接口的实现:
......@@ -2302,7 +2302,7 @@ class SpringSecurityAuditorAware implements AuditorAware<User> {
}
```
该实现访问由 Spring Security 提供的`Authentication`对象,并查找你在`UserDetailsService`实现中创建的自定义`UserDetails`实例。这里我们假设你通过`UserDetails`实现公开了域用户,但是,基于找到的`Authentication`,你也可以从任何地方查找它。
该实现访问由 Spring Security 提供的`Authentication`对象,并查找你在`UserDetailsService`实现中创建的自定义`UserDetails`实例。在这里,我们假设你通过`UserDetails`实现公开了域用户,但是,基于找到的`Authentication`,你也可以从任何地方查找它。
#### 7.1.4.`ReactiveAuditorAware`
......@@ -2366,9 +2366,9 @@ class SpringSecurityAuditorAware implements ReactiveAuditorAware<User> {
|`find…By`, `read…By`, `get…By`, `query…By`, `search…By`, `stream…By`|一般的查询方法通常返回存储库类型、`Collection``Streamable`子类型或结果包装器,如`Page``GeoResults`或任何其他特定于存储的结果包装器。可以用作`findBy…``findMyDomainTypeBy…`或与其他关键字组合使用。|
| `exists…By` |存在投影,通常返回`boolean`结果。|
| `count…By` |计数投影返回一个数字结果。|
| `delete…By`, `remove…By` |Delete 查询方法,返回无结果(“void”)或删除计数。|
| `delete…By`, `remove…By` |删除查询方法,返回不返回任何结果(`void`)或删除计数。|
| `…First<number>…`, `…Top<number>…` |将查询结果限制为结果的第一个`<number>`。这个关键字可以出现在`find`(和其他关键字)和`by`之间的主题的任何位置。|
| `…Distinct…` |使用不同的查询只返回唯一的结果。查看特定于商店的文档是否支持该功能。这个关键字可以出现在`find`(和其他关键字)和`by`之间的主题的任何位置。|
| `…Distinct…` |使用不同的查询只返回唯一的结果。请参阅特定于商店的文档,以确定是否支持该功能。这个关键字可以出现在`find`(和其他关键字)和`by`之间的主题的任何位置。|
### 支持的查询方法谓词关键字和修饰符
......@@ -2405,7 +2405,7 @@ class SpringSecurityAuditorAware implements ReactiveAuditorAware<User> {
| `TRUE` |`True`, `IsTrue`|
| `WITHIN` |`Within`, `IsWithin`|
除了过滤谓词外,还支持以下修饰符列表:
除了筛选谓词外,还支持以下修饰符列表:
| Keyword |说明|
|----------------------------------|---------------------------------------------------------------------------------------------------------------------|
......@@ -2427,15 +2427,15 @@ class SpringSecurityAuditorAware implements ReactiveAuditorAware<User> {
| `void` |表示没有返回值。|
| Primitives |Java 原语。|
| Wrapper types |Java 包装器类型。|
| `T` |一个独特的实体。期望查询方法最多返回一个结果。如果没有找到结果,则返回`null`。多个结果触发`IncorrectResultSizeDataAccessException`。|
| `T` |一个独特的实体。期望查询方法最多返回一个结果。如果没有找到结果,则返回`null`。多个结果触发`IncorrectResultSizeDataAccessException`。|
| `Iterator<T>` |an`Iterator`。|
| `Collection<T>` |a`Collection`。|
| `List<T>` |a`List`。|
| `Optional<T>` |一个 Java8 或番石榴`Optional`。期望查询方法最多返回一个结果。如果没有找到结果,则返回`Optional.empty()`或`Optional.absent()`。多个结果触发`IncorrectResultSizeDataAccessException`。|
| `Optional<T>` |一个 Java8 或番石榴`Optional`。期望查询方法最多返回一个结果。如果没有找到结果,则返回`Optional.empty()``Optional.absent()`。多个结果触发`IncorrectResultSizeDataAccessException`。|
| `Option<T>` |要么是 scala,要么是 vavr`Option`类型。在语义上与前面描述的 Java8 的`Optional`相同。|
| `Stream<T>` |a java8`Stream`。|
| `Streamable<T>` |这是`Iterable`的一个方便的扩展,Directy 将方法公开于流、映射和筛选结果、将它们连接等。|
|Types that implement `Streamable` and take a `Streamable` constructor or factory method argument|公开构造函数或`….of(…)`/`….valueof(…)` 工厂方法的类型,以`Streamable`为参数。详见[返回自定义的可刷新包装器类型](#repositories.collections-and-iterables.streamable-wrapper)。|
|Types that implement `Streamable` and take a `Streamable` constructor or factory method argument|公开构造函数或`….of(…)`/`….valueOf(…)`工厂方法的类型,以`Streamable`为参数。详见[返回自定义的可刷新包装器类型](#repositories.collections-and-iterables.streamable-wrapper)。|
| Vavr `Seq`, `List`, `Map`, `Set` |VAVR 集合类型。详见[对 VAVR 收藏的支持](#repositories.collections-and-iterables.vavr)。|
| `Future<T>` |a`Future`。期望对方法进行`@Async`注释,并且需要启用 Spring 的异步方法执行功能。|
| `CompletableFuture<T>` |a java8`CompletableFuture`。期望对方法进行`@Async`注释,并且需要启用 Spring 的异步方法执行功能。|
......@@ -2445,11 +2445,11 @@ class SpringSecurityAuditorAware implements ReactiveAuditorAware<User> {
| `GeoResult<T>` |带有附加信息的结果条目,例如到参考位置的距离。|
| `GeoResults<T>` |带有附加信息的`GeoResult<T>`列表,例如到参考位置的平均距离。|
| `GeoPage<T>` |a`Page``GeoResult<T>`等参考位置的平均距离。|
| `Mono<T>` |一个项目反应器`Mono`使用反应性存储库发射零或一个元素。期望查询方法最多返回一个结果。如果没有找到结果,则返回`Mono.empty()`。多个结果触发`IncorrectResultSizeDataAccessException`。|
| `Mono<T>` |一个项目反应`Mono`发射零或使用反应库的一个元素。期望查询方法最多返回一个结果。如果没有找到结果,则返回`Mono.empty()`。多个结果会触发`IncorrectResultSizeDataAccessException`。|
| `Flux<T>` |一个项目反应堆`Flux`使用反应性存储库发射零、一个或多个元素。返回`Flux`的查询也可以发出无限数量的元素。|
| `Single<T>` |一个 RxJava`Single`使用反应库发射单个元素。期望查询方法最多返回一个结果。如果没有找到结果,则返回`Mono.empty()`。多个结果会触发`IncorrectResultSizeDataAccessException`。|
| `Maybe<T>` |RxJava`Maybe`使用反应库发射零或一个元素。期望查询方法最多返回一个结果。如果没有找到结果,则返回`Mono.empty()`。多个结果会触发`IncorrectResultSizeDataAccessException`。|
| `Flowable<T>` |RxJava`Flowable`使用反应库发射零、一个或多个元素。返回`Flowable`的查询也可以发出无限数量的元素。|
| `Maybe<T>` |一个 RxJava`Maybe`使用反应库发射零或一个元素。期望查询方法最多返回一个结果。如果没有找到结果,则返回`Mono.empty()`。多个结果触发`IncorrectResultSizeDataAccessException`。|
| `Flowable<T>` |一个 RxJava`Flowable`使用反应库发射零、一个或多个元素。返回`Flowable`的查询也可以发出无限数量的元素。|
---
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册