这篇文章是在看Spring Data Commons文档的时候梳理的内容,都是与Spring Data相关的,里面可能会涉及到Spring Data JPA的内容,但更多的是Commons的内容,Spring Data JPA只是一个具体的实现而已。

1. Spring Data 模块关系

Spring Data家族有多个模块:

  • Spring Data JPA
  • Spring Data Mongo

但所有的模块都基于Spring Data Commoms模块进行扩展。例如Spring Data JPA是针对JPA做扩展的一个子模块;Spring Data Mongo是针对MongoDB的子模块,但是共同的接口都是Spring Data。
可以说Spring Data Commons是其所有子模块的抽象,定义了一系列的操作标准及接口。

2. 独立使用Spring Data

Spring Data提供了RepositoryFactory,可以独立于Spring容器之外使用:

RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);

3. Repository - dao - 存储仓库

Spring Data中,都是基于存储仓库Repository对实体类对象进行CRUD操作的。
其中,最核心的是Repository接口,在org.springframework.data.repository包中定义。
Repository接口需要指定操作的实体类的类型实体类ID的类型。在该接口中,是没有任何方法的,只是用于标记让Spring Data知道。
通常我们会使用CurdRepository这个接口,当然,这个接口也是不包含JPA特性的,我们需要使用JPA特性的话,一般用的是JpaRepository接口。
下面给出Spring Data JPA中,JpaRepository的继承结构:

4. 使用指定Spring Data模块

上面一开始说了Spring Data有很多个不同的子模块,每个子模块对应一种数据存储方式或数据源,统称Spring Data *吧。
要让Spring Data在运行的时候知道我们使用哪个模块,就要进行指定,指定模块的方法有两种:

  • 存储库使用Spring Data模块特定的接口指定类型
  • 实体类使用Spring Data模块模块特定的注解指定类型

如果都不指定,在单模块的情形下是不存在问题的,但是如果项目中引入了不同的Spring Data模块,那么Spring Data在实际运行中就无法确定到底需要使用哪个模块。

5. 查询方法的拆分

Spring Data以方法中的结构为findBy...deleteBy...,其结构都是动词加上ByBy是整个语句拆分的关键点。通常By后面跟着的是查询的参数列表,通过AndOr来连接。
By后面的参数中,首先将整个内容作为一个属性,如果找不到,然后再参数中以大写字母为分割,直到找到对应的参数为止。

6. 分页查询、排序查询、限制查询、流式结果查询

6.1 排序查询

Spring Data接受使用Sort类型参数来进行排序查询的工作,Sort主要有两个参数构成:

  • 排序方向:ASC(升序)、DESC(降序)
  • 排序字段

6.2 分页查询参数

PageableSpring Data提供出来进行分页查询参数输入的接口,里面主要定义多个与页面设定的方法:

实现有很多,最常用的是PageRequest

PageRequest废弃了原本的new方式来构建分页参数,建议使用类中提供的of(...)静态方法来创建相关的分页参数实体。
of(...)分页查询中允许带上排序字段以及排序方向两个参数,在源码中,这两个共同构建成了Sort实体。这是很多业务中需要使用上的,首先需要讲内容进行排序,然后再分页列出。
分页查询中,next()previous()返回的分别是下一页上一页的分页参数实体,

6.3 分页查询结果(返回值)

除了支持常用的集合ListSet等查询结果集作为分页查询结果,Spring Data还有以下几种结果:

  • Page<T>
  • Slice<T>
  • List<T>
  • Set<T>

6.4 limit查询

Mysql中,我们需要获得前N个结果,使用limit关键字。
Spring Data中可以使用:

  • top
  • first

来进行限定最终的结果数,在topfirst关键字后面可以加上数字表示最大结果大小,默认值为1

  • User findFirstByUsername(String username)
  • List<Article> findFirst10Bytitle(String title)

当然,这个是支持使用PageableSort的。

6.5 流式查询结果

Spring Data支持使用Stram<T>流式API使用。

@Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();Stream<User> readAllByFirstnameNotNull();@Query("select u from User u")
Stream<User> streamAllPaged(Pageable pageable);

一般在try-with-resources中使用:

try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {stream.forEach(…);
}

7. 自定义实现dao存储库

7.1 自定义存储库片段

都知道当使用Spring Data之后,大部分的CRUD操作我们都不需要去实现。但是当某些情况下,例如有些查询方法需要不同的行为或者无法通过Spring查询实现时,我们确实是要自己手动实现查询方法的。这种做法叫Repository fragments,存储库片段。

步骤如下:

  1. 做出一个自己的接口:
interface CustomizedUserRepository {void someCustomMethod(User user);
}
  1. 实现接口,就是很普通的接口实现
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {public void someCustomMethod(User user) {// Your custom implementation}
}

注:

  1. 上面的实现中,一定要以Impl为结尾
  2. 接口的实现可以作为一个普通的Bean存在
  1. *Repository存储库扩展(继承)这个接口:
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {// Declare query methods here
}

注:
当有两个片段提供相同的方法和签名,那么将按照继承顺序覆盖。
但是别忘了,每个片段的实现

上面这种做法可以组合Spring Data提供的CURD以及自定义实现的接口。相对自由,但是也相对复杂。

注:
而且对于领域设计的角度来说,能不把业务放到dao层就千万不要这么做!!

7.2 使用命名空间来配置自定义存储库片段Bean

XMLJava Config中的配置base-packageSpring Data的基础架构会在启动的时候到配置的路径下去扫描对应的存储库包,找到实现并配置为Bean
因此,在上面说了实现片段需要后缀为Impl
如果不是,可以通过repository-impl-postfix来配置对应的后缀,如:

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

如果是使用Java Config:

@EnableJpaRepositories(basePackages = "cn.marer", repositoryImplementationPostfix = "DAO")
public class ....

后缀是可以配置多个的,不同的后缀就扫描不同的结果。

7.3 自定义BaseRepository - 基类

在Spring Data出现之前我们会使用BaseDao来实现一些基本的数据库的操作,现在也可以这样做:

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;}@Transactionalpublic <S extends T> S save(S entity) {// implementation goes here}
}

注:

  1. 该类需要具有特定于商店的存储库工厂实现所使用的超类的构造函数。
  2. 如果存储库基类具有多个构造函数,则覆盖使用EntityInformation加号存储特定基础结构对象(例如,EntityManager模板类)的构造函数。

然后还需要在Java Config中指定存储库基类:

@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }

这个就类似于为基类配置一个Bean。

8. 发布事件

直接官方机翻:
由存储库管理的实体是聚合根。在域驱动设计应用程序中,这些聚合根通常会发布域事件。Spring Data提供了一个注释@DomainEvents,可以在聚合根的方法上使用,以使该发布尽可能简单,如以下示例所示:

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。它可用于潜在地清除要发布的事件列表(以及其他用途)。

9. Spring Data对Spring MVC支持

9.1 打开Spring data对web的支持

Spring Data提供了对web的友好支持,特别是下面将说到的领域类型(可以先看作实体类)转换的支持以及分页、排序的支持,要打开支持,有两种方式:

  • Java Config
  • XML

还是比较推荐使用Java Config的方式,毕竟Spring Boot大多数都是注解形式嘛:

@EnableSpringDataWebSupport
piublic class WebConfiguration {...
}

XML开启:

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

按照官方文档,如果打开了这个支持,Spring会自动配置了下面三个Bean:

  • DomainClassConverter - 允许在不用通过存储库手动查找的情况下,直接在SpringMVC的控制器方法的签名(参数)中直接使用领域对象

  • PageableHandlerMethodArgumentResolver - 允许通过请求参数Pageable对象注入到controller方法参数 Pageable

  • SortHandlerMethodArgumentResolver - 允许通过请求参数Sort对象注入到controller方法参数 Sort

9.2 DomainClassConverter - 领域类型转换器支持

DomainClassConverter可以在不用通过存储库手动查找的情况下,直接在SpringMVC的控制器方法的签名(参数)中直接使用领域对象。
需要按照上面的两种方式其中一个打开对web的支持。

现在假定有User这个领域对象和UserRepository这个存储库,那么可以直接使用:

@RestController
public class UserController {@PostMapping("/user/info/{id}")public User getUserInfo(@PathVariable("id") User user) {logger.info("Get user info By Spring data web support");return user;}
}

上面方法中,并没有通过UserRepository存储库对象来获取相对应的用户数据。
SpringMVC将提交上来的参数{id}通过@PathVariable获得ID,然后调用findById(...)查找出对应的实体并注入到方法参数中。所以可以直接通过返回User参数,算是偷懒方式。

注意:

  1. 领域类型对应的存储库最起码是要实现CurdRepository才可以实现这个功能,
  2. 如果找不到数据,会返回500 Internal Server Error,需要对数据做校验或者做异常处理。

9.3 HandlerMethodArgumentResolvers - 分页、排序的支持

在上面说了,需要让Spring Data支持分页或排序功能,就需要在存储库Repository接口方法中传入PageableSort对象,Pageable分页的对象里面也包含了Sort排序。Spring Data会自动解析并对分页、排序进行limitorder by查询。
而Spring Data也对web提供了分页、排序的支持,让我们可以在访问http提交请求参数的时候直接将pageablesort参数注入到controller的方法参数。
主要是配置了@EnableSpringDataWebSupport后,Spring Data会生成PageableHandlerMethodArgumentResolverSortHandlerMethodArgumentResolver两个Bean实例。在我们的Controller的方法中加入参数即可:

@RestController
public class UserController {@GetMapping("/user/info/all/page")public List<User> getAllUserPage(Pageable pageable){logger.info(“try to find user with pageable.”);return userRepository.findAll(pageable).getContent();}
}

在上面的例子中,要做的是:分页显示用户。使用了Pageable作为例子,因为我们知道Pageable里面包含了Sort,因此Sort的例子在这里就不再叙述了。
上面的例子里面,提交的参数为:

  • page - 第几页,默认为0
  • size - 页面数据数量,默认为20
  • sort - 排序方向,默认为升序ASC

假设:查询第一页的用户并根据用户名降序排序,页面大小为15。则请求API如下:

/user/info/all/page?page=0&size=15&sort=username,DESC

注意:
上面这个例子是GET请求方法的,如果是POST请求方法,请把请求参数放到请求体里面

更多关于Spring Data对Web支持请移步到:
https://docs.spring.io/spring-data/jpa/docs/2.1.3.RELEASE/reference/html/#core.web


此文同时在简书发布:https://www.jianshu.com/p/cb5a3ab2727e
此文同时在CSDN发布:https://blog.csdn.net/nthack5730/article/details/84939027
转载要加原文链接!谢谢支持!


Spring Data Commons主要梳理相关推荐

  1. 【web安全】Spring Data Commons 1.13.10 SpEL漏洞分析

    一.简介 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,Spring Data Commons是Spring Data下所有子项目共享的基础框架.Spring Data Co ...

  2. 漏洞复现之CVE-2018-1273 Spring Data Commons 远程命令执行

    漏洞背景 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,Spring Data Commons是Spring Data下所有子项目共享的基础框架.Spring Data Co ...

  3. Spring Data Commons 官方文档学习

    Spring Data Commons 官方文档学习   -by LarryZeal Version 1.12.6.Release, 2017-07-27 为知笔记版本在这里,带格式. Table o ...

  4. 漏洞复现 | CVE-2018-1273 Spring Data Commons 远程命令执行

    作者: 墨阳 免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责. 0x00 前言 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,Spring Data ...

  5. Spring Data JPA例子[基于Spring Boot、Mysql]

    关于Spring Data Spring社区的一个顶级工程,主要用于简化数据(关系型&非关系型)访问,如果我们使用Spring Data来开发程序的话,那么可以省去很多低级别的数据访问操作,如 ...

  6. 01 | Spring Data JPA 初识

    课程正式开始了,这里我会以一个案例的形式来和你讲解如何通过 Spring Boot 结合 Spring Data JPA 快速启动一个项目.如何使用 UserRepository 完成对 User 表 ...

  7. Spring Data JPA初使用 *****重要********

    Spring Data JPA初使用 我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样 ...

  8. Spring Data JPA教程

    在Java类或对象与关系数据库之间管理数据是一项非常繁琐且棘手的任务. DAO层通常包含许多样板代码,应简化这些样板代码,以减少代码行数并使代码可重复使用. 在本教程中,我们将讨论Spring数据的J ...

  9. Spring Data JPA教程:简介

    创建使用Java Persistence API的存储库是一个繁琐的过程,需要大量时间,并且需要大量样板代码. 通过执行以下步骤,我们可以消除一些样板代码: 创建一个抽象的基础存储库类,该类为实体提供 ...

最新文章

  1. 微信8.0之后,又悄悄上线新功能:别人“抢不到”的红包!赶紧看看灰度到你了没?...
  2. MFC序列化(serial)简单例子
  3. autojs 云控_autojs websocket 核心示例代码,云控技术
  4. 英文聊天常用缩写单词
  5. Python-Socket编程学习(11.3)
  6. 如果孩子早恋是支持还是反对?
  7. Atitit office Ooxml excel标准的主要内容 目录 1.1. 物理存储 zip+文件夹包+xml 1 1.2. Package Structure 1 1.3. 内容部分 1
  8. 判断图有无环_汽车 AEB 驾驶员在环系统建立
  9. java.lang.IllegalArgumentException: Can not set xx field xx to jav问题解决
  10. json的存储与读取
  11. Acer 4750 安装黑苹果_10代酷睿手把手安装黑苹果
  12. python中步长什么意思,python步长是什么
  13. [转载]项目风险管理七种武器-长生剑
  14. 安焦删除贴 牛人纷纷出现(2)
  15. GitLab 之 历史版本回退
  16. go语言webSocket框架——gorilla
  17. openwrt软路由实现ipv6 nat 上网配置
  18. linux局域网下远程启动机器
  19. 记一次ios内购开发中踩的坑
  20. 小程序setData报错未定义

热门文章

  1. win10下编译安装ncnn
  2. 计算机系男生穿搭,男生必备的20套穿搭,型男范十足!
  3. 【办公-excel】VBA 选择文件、文件夹
  4. 计算机原理与设计verilog pdf,计算机原理与设计: Verilog HDL版
  5. 手机PDF如何转PPT
  6. upf学习之获取supply_net的状态
  7. 【java基础系列】13- java的面向对象
  8. PFR0.S08.00.F00比例流量控制插装阀
  9. EDR(端点、端点检测与响应中心、可视化展现)
  10. ssb的matlab仿真,基于matlab软件仿真——单边带、双边带调制解调程序和Simulink建模仿真...