原题目:Spring认证|Spring Data JPA 参考文档三(内容起源:Spring中国教育管理中心)

Spring Data JPA 参考文档三
手动接线

如果您的自定义实现仅应用基于注解的配置和主动拆卸,则后面显示的办法成果很好,因为它被视为任何其余 Spring bean。如果您的实现片段 bean 须要非凡连贯,您能够依据上一节中形容的约定申明 bean 并为其命名。而后,基础设施通过名称援用手动定义的 bean 定义,而不是本人创立一个。以下示例显示了如何手动连贯自定义实现:

示例 38. 自定义实现的手动接线

<repositories base-package="com.acme.repository" />

<beans:bean id="userRepositoryImpl" class="…">

<!-- further configuration -->

</beans:bean>

4.6.2. 自定义根底存储库

当您想要自定义根本存储库行为以便影响所有存储库时,上一节中形容的办法须要自定义每个存储库接口。要改为更改所有存储库的行为,您能够创立一个扩大持久性技术特定存储库基类的实现。而后,此类充当存储库代理的自定义基类,如以下示例所示:

示例 39.自定义存储库基类

class MyRepositoryImpl<T, ID>

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

}

}

Spring Data JPA 参考文档三
该类须要具备特定于商店的存储库工厂实现应用的超类的构造函数。如果存储库基类有多个构造函数,则笼罩一个EntityInformation加上存储特定根底构造对象(例如一个EntityManager或模板类)的构造函数。

最初一步是让 Spring Data 基础设施晓得定制的存储库基类。在 Java 配置中,您能够应用注解的repositoryBaseClass属性来实现@Enable${store}Repositories,如下例所示:

示例 40. 应用 JavaConfig 配置自定义存储库基类

@Configuration

@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)

class ApplicationConfiguration { … }

XML 命名空间中提供了相应的属性,如以下示例所示:

示例 41. 应用 XML 配置自定义存储库基类

<repositories base-package="com.acme.repository"

base-class="….MyRepositoryImpl" />

4.7. 从聚合根公布事件

存储库治理的实体是聚合根。在域驱动设计应用程序中,这些聚合根通常公布域事件。Spring Data 提供了一个名为的正文@DomainEvents,您能够在聚合根的办法上应用该正文,以使该公布尽可能简略,如以下示例所示:

示例 42. 从聚合根公开域事件

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. 您能够应用它潜在地清理要公布的事件列表(以及其余用处)。

该办法被称为一个Spring数据存储库的每一次一个save(…),saveAll(…),delete(…)或deleteAll(…)办法被调用。

4.8. Spring 数据扩大

本节记录了一组 Spring Data 扩大,这些扩大反对在各种上下文中应用 Spring Data。目前,大部分集成都针对 Spring MVC。

4.8.1. Querydsl 扩大

Querydsl是一个框架,能够通过其晦涩的 API 构建动态类型的 SQL 类查问。

几个 Spring Data 模块通过 提供与 Querydsl 的集成QuerydslPredicateExecutor,如以下示例所示:


43.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存在。

Spring Data JPA 参考文档三
要应用 Querydsl 反对,请扩大QuerydslPredicateExecutor您的存储库界面,如以下示例所示:

示例 44. 存储库上的 Querydsl 集成

interface UserRepository extends CrudRepository<User, Long>, QuerydslPredicateExecutor<User> {

}

后面的示例容许您应用 QuerydslPredicate实例编写类型平安的查问,如以下示例所示:

Predicate predicate = user.firstname.equalsIgnoreCase("dave")

.and(user.lastname.startsWithIgnoreCase("mathews"));

userRepository.findAll(predicate);

4.8.2. 网络反对

反对存储库编程模型的 Spring Data 模块附带了各种 Web 反对。Web 相干组件要求 Spring MVC JAR 位于类门路上。其中一些甚至提供与Spring HATEOAS 的集成。通常,通过应用@
EnableSpringDataWebSupportJavaConfig 配置类中的正文来启用集成反对,如以下示例所示:

示例 45.启用 Spring Data Web 反对

@Configuration

@EnableWebMvc

@EnableSpringDataWebSupport

class WebConfiguration {}

该@
EnableSpringDataWebSupport批注注册几个组件。咱们将在本节前面探讨这些。它还检测类门路上的 Spring HATEOAS 并为其注册集成组件(如果存在)。

或者,如果您应用 XML 配置,请注册
SpringDataWebConfiguration或HateoasAwareSpringDataWebConfiguration作为 Spring bean,如以下示例所示(对于SpringDataWebConfiguration):

示例 46. 在 XML 中启用 Spring Data Web 反对

<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />

<!-- If you use Spring HATEOAS, register this one instead of the former -->

<bean class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration" />

根本网络反对

上一节中显示的配置注册了一些根本组件:

A应用DomainClassConverter类让 Spring MVC 从申请参数或门路变量解析存储库治理的域类的实例。

HandlerMethodArgumentResolver让 Spring MVC从申请参数解析Pageable和Sort实例的实现。

Jackson Modules用于反/序列化Point和 等类型Distance,或存储特定类型,具体取决于所应用的 Spring 数据模块。

应用DomainClassConverter类

本DomainClassConverter类让你在Spring MVC中的控制器办法签名应用域类型间接使您不用手动通过资源库查找的状况下,如下例所示:

示例 47. 在办法签名中应用域类型的 Spring MVC 控制器

@Controller

@RequestMapping("/users")

class UserController {

@RequestMapping("/{id}")

String showUserForm(@PathVariable("id") User user, Model model) {

model.addAttribute("user", user);

return "userForm";

}

}

Spring Data JPA 参考文档三
该办法User间接接管实例,不须要进一步查找。能够通过让 Spring MVCid先将门路变量转换为域类的类型,最终通过调用findById(…)为域类型注册的存储库实例来拜访实例来解析实例。

目前,存储库必须实现CrudRepository能力被发现进行转换。

用于可分页和排序的
HandlerMethodArgumentResolvers

的配置片段中,在示出前一节还注册一个
PageableHandlerMethodArgumentResolver,以及实例SortHandlerMethodArgumentResolver。注册启用Pageable并Sort作为无效的控制器办法参数,如以下示例所示:

示例 48.应用 Pageable 作为控制器办法参数

@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";

}

}

Spring Data JPA 参考文档三
后面的办法签名导致 Spring MVC 尝试Pageable应用以下默认配置从申请参数派生实例:

Spring Data JPA 参考文档三
要自定义此行为,请别离注册一个实现
PageableHandlerMethodArgumentResolverCustomizer接口或SortHandlerMethodArgumentResolverCustomizer接口的 bean 。它的customize()办法被调用,让您更改设置,如以下示例所示:

@Bean SortHandlerMethodArgumentResolverCustomizer sortCustomizer() {

return s -> s.setPropertyDelimiter("<-->");

}

如果设置现有的属性MethodArgumentResolver不足以满足您的目标,请扩大
SpringDataWebConfiguration或启用 HATEOAS 的等效项,笼罩pageableResolver()或sortResolver()办法,并导入您的自定义配置文件而不是应用@Enable正文。

如果您须要从申请中解析多个Pageable或多个Sort实例(例如,对于多个表),您能够应用 Spring 的@Qualifier注解来辨别一个和另一个。申请参数必须以 为前缀${qualifier}_。以下示例显示了生成的办法签名:

String showUsers(Model model,

@Qualifier("thing1") Pageable first,

@Qualifier("thing2") Pageable second) { … }

您必须填充thing1_page、thing2_page等。

Pageable传递给办法的默认值等效于 a PageRequest.of(0, 20),但您能够通过应用参数@PageableDefault上的正文来自定义它Pageable。

对可分页的超媒体反对

Spring HATEOAS 附带了一个示意模型类 ( PagedResources),它容许Page应用必要的Page元数据和链接来丰盛实例的内容,让客户端轻松导航页面。aPage到 a的转换PagedResources是由 Spring HATEOASResourceAssembler接口的实现实现的,称为PagedResourcesAssembler. 以下示例显示了如何应用 aPagedResourcesAssembler作为控制器办法参数:

示例 49.应用 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(…)它有以下成果:

的内容Page成为PagedResources实例的内容。

该PagedResources对象PageMetadata附加了一个实例,并填充了来自Page和底层 的信息PageRequest。

将PagedResources可能会prev和next连贯链路,依据页面的状态。链接指向办法映射到的 URI。增加到该办法的分页参数与 的设置相匹配,
PageableHandlerMethodArgumentResolver以确保稍后能够解析链接。

假如咱们Person在数据库中有 30 个实例。您当初能够触发申请 ( ) 并看到相似于以下内容的输入:GET
http://localhost:8080/persons

{ "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为行将到来的申请。这意味着,如果您更改该配置,链接将主动恪守更改。默认状况下,汇编器指向调用它的控制器办法,但您能够通过传递一个自定义Link来自定义它,该自定义用作构建分页链接的根底,这会重载该
PagedResourcesAssembler.toResource(…)办法。

Spring Data Jackson 模块

外围模块和一些特定于商店的模块附带一组 Jackson 模块,用于 Spring Data 域应用的类型,例如
org.springframework.data.geo.Distance和org.springframework.data.geo.Point。

一旦启用Web 反对并可用,
com.fasterxml.jackson.databind.ObjectMapper就会导入这些模块。

在初始化期间SpringDataJacksonModules,像 一样
SpringDataJacksonConfiguration,被基础设施接管,以便申明的com.fasterxml.jackson.databind.Modules 可供 Jackson 应用ObjectMapper。

以下域类型的数据绑定混合由公共根底构造注册。

org.springframework.data.geo.Distance

org.springframework.data.geo.Point

org.springframework.data.geo.Box

org.springframework.data.geo.Circle

org.springframework.data.geo.Polygon

单个模块可能会提供额定的SpringDataJacksonModules.

无关更多详细信息,请参阅商店特定局部。

网页数据绑定反对

您能够应用 Spring Data 投影(在Projections 中形容)通过应用JSONPath表达式(须要Jayway JsonPath或XPath表达式(须要XmlBeam)来绑定传入的申请无效负载,如以下示例所示:

示例 50.应用 JSONPath 或 XPath 表达式的 HTTP 负载绑定

@ProjectedPayload

public interface UserPayload {

@XBRead("//firstname")

@JsonPath("$..firstname")

String getFirstname();

@XBRead("/lastname")

@JsonPath({ "$.lastname", "$.user.lastname" })

String getLastname();

}

能够应用在后面的例子中为一个Spring MVC处理程序办法参数或通过应用所示类型
ParameterizedTypeReference上的办法之一RestTemplate。后面的办法申明将尝试查找firstname给定文档中的任何地位。该lastnameXML查问是对输出文档的顶层进行。其 JSON 变体lastname首先尝试顶级,但如果前者不返回值,也会尝试lastname嵌套在user子文档中。这样,无需客户端调用公开的办法(通常是基于类的无效负载绑定的毛病)即可轻松加重源文档构造的更改。

如Projections 中所述,反对嵌套投影。如果该办法返回简单的非接口类型,ObjectMapper则应用Jackson来映射最终值。

对于 Spring MVC,必要的转换器一旦@
EnableSpringDataWebSupport处于活动状态就会主动注册,并且所需的依赖项在类门路上可用。对于应用RestTemplate,注册ProjectingJackson2HttpMessageConverter(JSON)或XmlBeamHttpMessageConverter手动。

无关更多信息,请参阅标准Spring 数据示例存储库中的Web 投影示例。

Querydsl 网络反对

对于那些具备QueryDSL集成的商店,您能够从Request查问字符串中蕴含的属性派生查问。

思考以下查问字符串:

?firstname=Dave&lastname=Matthews

给定User后面示例中的对象,您能够应用 将查问字符串解析为以下值
QuerydslPredicateArgumentResolver,如下所示:

QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))

@
EnableSpringDataWebSupport当在类门路上找到 Querydsl 时 ,会主动启用该性能以及。

将 a 增加@QuerydslPredicate到办法签名提供了一个随时可用的Predicate,您能够应用
QuerydslPredicateExecutor.

类型信息通常从办法的返回类型解析。因为该信息不肯定与域类型匹配,因而应用 的root属性可能是一个好主见QuerydslPredicate。

以下示例显示了如何@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";

}

}

将查问字符串参数解析为匹配Predicatefor User。

Spring Data JPA 参考文档三
默认绑定如下:

Object在简略的属性上eq。

Object在像属性一样的汇合上contains。

Collection在简略的属性上in。

您能够通过Java 8的bindings属性@QuerydslPredicate或通过应用 Java 8default 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提供对特定 finder 办法的拜访Predicate。

QuerydslBinderCustomizer存储库界面上定义的主动拾取和快捷方式@QuerydslPredicate(bindings=…)。

将username属性的绑定定义为简略contains绑定。

将String属性的默认绑定定义为不辨别大小写的contains匹配。

password从Predicate解析中排除该属性。

Spring Data JPA 参考文档三
你能够注册一个
QuerydslBinderCustomizerDefaults从资源库或利用特定的绑定之前豆放弃默认Querydsl绑定@QuerydslPredicate。