Spring Data Commons主要梳理

這篇文章是在看Spring Data Commons文檔的時(shí)候梳理的內(nèi)容,都是與Spring Data相關(guān)的,里面可能會涉及到Spring Data JPA的內(nèi)容,但更多的是Commons的內(nèi)容,Spring Data JPA只是一個(gè)具體的實(shí)現(xiàn)而已。

1. Spring Data 模塊關(guān)系

Spring Data家族有多個(gè)模塊:

  • Spring Data JPA
  • Spring Data Mongo
  • ....

但所有的模塊都基于Spring Data Commoms模塊進(jìn)行擴(kuò)展吓歇。例如Spring Data JPA是針對JPA做擴(kuò)展的一個(gè)子模塊;Spring Data Mongo是針對MongoDB的子模塊票腰,但是共同的接口都是Spring Data城看。
可以說Spring Data Commons是其所有子模塊的抽象,定義了一系列的操作標(biāo)準(zhǔn)及接口杏慰。

2. 獨(dú)立使用Spring Data

Spring Data提供了RepositoryFactory测柠,可以獨(dú)立于Spring容器之外使用:

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

3. Repository - dao - 存儲倉庫

Spring Data中,都是基于存儲倉庫Repository對實(shí)體類對象進(jìn)行CRUD操作的逃默。
其中鹃愤,最核心的是Repository接口,在org.springframework.data.repository包中定義完域。
Repository接口需要指定操作的實(shí)體類的類型软吐、實(shí)體類ID的類型。在該接口中吟税,是沒有任何方法的凹耙,只是用于標(biāo)記讓Spring Data知道姿现。
通常我們會使用CurdRepository這個(gè)接口,當(dāng)然肖抱,這個(gè)接口也是不包含JPA特性的备典,我們需要使用JPA特性的話,一般用的是JpaRepository接口意述。
下面給出Spring Data JPA中提佣,JpaRepository的繼承結(jié)構(gòu):

1.jpg

4. 使用指定Spring Data模塊

上面一開始說了Spring Data有很多個(gè)不同的子模塊,每個(gè)子模塊對應(yīng)一種數(shù)據(jù)存儲方式或數(shù)據(jù)源荤崇,統(tǒng)稱Spring Data *吧拌屏。
要讓Spring Data在運(yùn)行的時(shí)候知道我們使用哪個(gè)模塊,就要進(jìn)行指定术荤,指定模塊的方法有兩種:

  • 存儲庫使用Spring Data模塊特定的接口指定類型
  • 實(shí)體類使用Spring Data模塊模塊特定的注解指定類型

如果都不指定倚喂,在單模塊的情形下是不存在問題的,但是如果項(xiàng)目中引入了不同的Spring Data模塊瓣戚,那么Spring Data在實(shí)際運(yùn)行中就無法確定到底需要使用哪個(gè)模塊端圈。

5. 查詢方法的拆分

Spring Data以方法中的結(jié)構(gòu)為findBy...deleteBy...子库,其結(jié)構(gòu)都是動詞加上By舱权,By是整個(gè)語句拆分的關(guān)鍵點(diǎn)。通常By后面跟著的是查詢的參數(shù)列表刚照,通過And刑巧、Or來連接。
By后面的參數(shù)中无畔,首先將整個(gè)內(nèi)容作為一個(gè)屬性,如果找不到吠冤,然后再參數(shù)中以大寫字母為分割浑彰,直到找到對應(yīng)的參數(shù)為止。

6. 分頁查詢拯辙、排序查詢郭变、限制查詢、流式結(jié)果查詢

6.1 排序查詢

Spring Data接受使用Sort類型參數(shù)來進(jìn)行排序查詢的工作涯保,Sort主要有兩個(gè)參數(shù)構(gòu)成:

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

6.2 分頁查詢參數(shù)

PageableSpring Data提供出來進(jìn)行分頁查詢參數(shù)輸入的接口,里面主要定義多個(gè)與頁面設(shè)定的方法:

6.2.jpg

實(shí)現(xiàn)有很多夕春,最常用的是PageRequest

6.2-2.jpg

PageRequest廢棄了原本的new方式來構(gòu)建分頁參數(shù)未荒,建議使用類中提供的of(...)靜態(tài)方法來創(chuàng)建相關(guān)的分頁參數(shù)實(shí)體。
of(...)分頁查詢中允許帶上排序字段以及排序方向兩個(gè)參數(shù)及志,在源碼中片排,這兩個(gè)共同構(gòu)建成了Sort實(shí)體寨腔。這是很多業(yè)務(wù)中需要使用上的,首先需要講內(nèi)容進(jìn)行排序率寡,然后再分頁列出迫卢。
分頁查詢中,next()冶共、previous()返回的分別是下一頁乾蛤、上一頁的分頁參數(shù)實(shí)體,

6.3 分頁查詢結(jié)果(返回值)

除了支持常用的集合List捅僵、Set等查詢結(jié)果集作為分頁查詢結(jié)果幻捏,Spring Data還有以下幾種結(jié)果:

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

6.4 limit查詢

Mysql中,我們需要獲得前N個(gè)結(jié)果命咐,使用limit關(guān)鍵字篡九。
Spring Data中可以使用:

  • top
  • first

來進(jìn)行限定最終的結(jié)果數(shù),在top醋奠、first關(guān)鍵字后面可以加上數(shù)字表示最大結(jié)果大小榛臼,默認(rèn)值為1

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

當(dāng)然,這個(gè)是支持使用Pageable窜司、Sort的沛善。

6.5 流式查詢結(jié)果

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. 自定義實(shí)現(xiàn)dao存儲庫

7.1 自定義存儲庫片段

都知道當(dāng)使用Spring Data之后塞祈,大部分的CRUD操作我們都不需要去實(shí)現(xiàn)金刁。但是當(dāng)某些情況下,例如有些查詢方法需要不同的行為或者無法通過Spring查詢實(shí)現(xiàn)時(shí)议薪,我們確實(shí)是要自己手動實(shí)現(xiàn)查詢方法的尤蛮。這種做法叫Repository fragments,存儲庫片段斯议。

步驟如下:

  1. 做出一個(gè)自己的接口:
interface CustomizedUserRepository {
  void someCustomMethod(User user);
}
  1. 實(shí)現(xiàn)接口产捞,就是很普通的接口實(shí)現(xiàn)
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

  public void someCustomMethod(User user) {
    // Your custom implementation
  }
}

注:

  1. 上面的實(shí)現(xiàn)中,一定要以Impl為結(jié)尾
  2. 接口的實(shí)現(xiàn)可以作為一個(gè)普通的Bean存在
  1. *Repository存儲庫擴(kuò)展(繼承)這個(gè)接口:
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {

  // Declare query methods here
}

注:
當(dāng)有兩個(gè)片段提供相同的方法和簽名哼御,那么將按照繼承順序覆蓋坯临。
但是別忘了,每個(gè)片段的實(shí)現(xiàn)

上面這種做法可以組合Spring Data提供的CURD以及自定義實(shí)現(xiàn)的接口恋昼。相對自由看靠,但是也相對復(fù)雜。

注:
而且對于領(lǐng)域設(shè)計(jì)的角度來說液肌,能不把業(yè)務(wù)放到dao層就千萬不要這么做P妗!

7.2 使用命名空間來配置自定義存儲庫片段Bean

XMLJava Config中的配置base-packageSpring Data的基礎(chǔ)架構(gòu)會在啟動的時(shí)候到配置的路徑下去掃描對應(yīng)的存儲庫包辟宗,找到實(shí)現(xiàn)并配置為Bean爵赵。
因此,在上面說了實(shí)現(xiàn)片段需要后綴為Impl泊脐。
如果不是空幻,可以通過repository-impl-postfix來配置對應(yīng)的后綴,如:

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

如果是使用Java Config:

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

后綴是可以配置多個(gè)的容客,不同的后綴就掃描不同的結(jié)果秕铛。

7.3 自定義BaseRepository - 基類

在Spring Data出現(xiàn)之前我們會使用BaseDao來實(shí)現(xiàn)一些基本的數(shù)據(jù)庫的操作,現(xiàn)在也可以這樣做:

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
  }
}

注:

  1. 該類需要具有特定于商店的存儲庫工廠實(shí)現(xiàn)所使用的超類的構(gòu)造函數(shù)缩挑。
  2. 如果存儲庫基類具有多個(gè)構(gòu)造函數(shù)但两,則覆蓋使用EntityInformation加號存儲特定基礎(chǔ)結(jié)構(gòu)對象(例如,EntityManager模板類)的構(gòu)造函數(shù)供置。

然后還需要在Java Config中指定存儲庫基類:

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

這個(gè)就類似于為基類配置一個(gè)Bean谨湘。

8. 發(fā)布事件

直接官方機(jī)翻:
由存儲庫管理的實(shí)體是聚合根。在域驅(qū)動設(shè)計(jì)應(yīng)用程序中芥丧,這些聚合根通常會發(fā)布域事件紧阔。Spring Data提供了一個(gè)注釋@DomainEvents,可以在聚合根的方法上使用续担,以使該發(fā)布盡可能簡單擅耽,如以下示例所示:

class AnAggregateRoot {

    @DomainEvents 
    Collection<Object> domainEvents() {
        // … return events you want to get published here
    }

    @AfterDomainEventPublication 
    void callbackMethod() {
       // … potentially clean up domain events list
    }
}

使用的方法@DomainEvents可以返回單個(gè)事件實(shí)例或事件集合。它不能使用任何參數(shù)物遇。
在所有事件發(fā)布后乖仇,我們有一個(gè)注釋的方法@AfterDomainEventPublication。它可用于潛在地清除要發(fā)布的事件列表(以及其他用途)询兴。

9. Spring Data對Spring MVC支持

9.1 打開Spring data對web的支持

Spring Data提供了對web的友好支持乃沙,特別是下面將說到的領(lǐng)域類型(可以先看作實(shí)體類)轉(zhuǎn)換的支持以及分頁、排序的支持蕉朵,要打開支持崔涂,有兩種方式:

  • Java Config
  • XML

還是比較推薦使用Java Config的方式,畢竟Spring Boot大多數(shù)都是注解形式嘛:

@EnableSpringDataWebSupport
piublic class WebConfiguration {
    ...
}

XML開啟:

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

按照官方文檔始衅,如果打開了這個(gè)支持,Spring會自動配置了下面三個(gè)Bean:

  • DomainClassConverter - 允許在不用通過存儲庫手動查找的情況下缭保,直接在SpringMVC的控制器方法的簽名(參數(shù))中直接使用領(lǐng)域?qū)ο?/p>

  • PageableHandlerMethodArgumentResolver - 允許通過請求參數(shù)Pageable對象注入到controller方法參數(shù) Pageable

  • SortHandlerMethodArgumentResolver - 允許通過請求參數(shù)Sort對象注入到controller方法參數(shù) Sort

9.2 DomainClassConverter - 領(lǐng)域類型轉(zhuǎn)換器支持

DomainClassConverter可以在不用通過存儲庫手動查找的情況下汛闸,直接在SpringMVC的控制器方法的簽名(參數(shù))中直接使用領(lǐng)域?qū)ο蟆?br> 需要按照上面的兩種方式其中一個(gè)打開對web的支持。

現(xiàn)在假定有User這個(gè)領(lǐng)域?qū)ο蠛?code>UserRepository這個(gè)存儲庫艺骂,那么可以直接使用:

@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存儲庫對象來獲取相對應(yīng)的用戶數(shù)據(jù)。
SpringMVC將提交上來的參數(shù){id}通過@PathVariable獲得ID钳恕,然后調(diào)用findById(...)查找出對應(yīng)的實(shí)體并注入到方法參數(shù)中别伏。所以可以直接通過返回User參數(shù)蹄衷,算是偷懶方式。

注意:

  1. 領(lǐng)域類型對應(yīng)的存儲庫最起碼是要實(shí)現(xiàn)CurdRepository才可以實(shí)現(xiàn)這個(gè)功能厘肮,
  2. 如果找不到數(shù)據(jù)愧口,會返回500 Internal Server Error,需要對數(shù)據(jù)做校驗(yàn)或者做異常處理类茂。

9.3 HandlerMethodArgumentResolvers - 分頁耍属、排序的支持

在上面說了,需要讓Spring Data支持分頁或排序功能巩检,就需要在存儲庫Repository接口方法中傳入PageableSort對象厚骗,Pageable分頁的對象里面也包含了Sort排序。Spring Data會自動解析并對分頁兢哭、排序進(jìn)行limit领舰、order by查詢。
而Spring Data也對web提供了分頁迟螺、排序的支持冲秽,讓我們可以在訪問http提交請求參數(shù)的時(shí)候直接將pageablesort參數(shù)注入到controller的方法參數(shù)煮仇。
主要是配置了@EnableSpringDataWebSupport后劳跃,Spring Data會生成PageableHandlerMethodArgumentResolverSortHandlerMethodArgumentResolver兩個(gè)Bean實(shí)例浙垫。在我們的Controller的方法中加入?yún)?shù)即可:

@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作為例子夹姥,因?yàn)槲覀冎?code>Pageable里面包含了Sort杉武,因此Sort的例子在這里就不再敘述了。
上面的例子里面辙售,提交的參數(shù)為:

  • page - 第幾頁轻抱,默認(rèn)為0
  • size - 頁面數(shù)據(jù)數(shù)量,默認(rèn)為20
  • sort - 排序方向旦部,默認(rèn)為升序ASC

假設(shè):查詢第一頁的用戶并根據(jù)用戶名降序排序祈搜,頁面大小為15。則請求API如下:

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

注意:
上面這個(gè)例子是GET請求方法的士八,如果是POST請求方法容燕,請把請求參數(shù)放到請求體里面

更多關(guān)于Spring Data對Web支持請移步到:
https://docs.spring.io/spring-data/jpa/docs/2.1.3.RELEASE/reference/html/#core.web


此文同時(shí)在簡書發(fā)布:http://www.reibang.com/p/cb5a3ab2727e
此文同時(shí)在CSDN發(fā)布:https://blog.csdn.net/nthack5730/article/details/84939027
轉(zhuǎn)載要加原文鏈接!謝謝支持婚度!


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蘸秘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌醋虏,老刑警劉巖寻咒,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颈嚼,居然都是意外死亡毛秘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門粘舟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熔脂,“玉大人,你說我怎么就攤上這事柑肴∠既啵” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵晰骑,是天一觀的道長适秩。 經(jīng)常有香客問我,道長硕舆,這世上最難降的妖魔是什么秽荞? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮抚官,結(jié)果婚禮上扬跋,老公的妹妹穿的比我還像新娘。我一直安慰自己凌节,他們只是感情好钦听,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著倍奢,像睡著了一般朴上。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卒煞,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天痪宰,我揣著相機(jī)與錄音,去河邊找鬼畔裕。 笑死衣撬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扮饶。 我是一名探鬼主播淮韭,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼贴届!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤毫蚓,失蹤者是張志新(化名)和其女友劉穎占键,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體元潘,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畔乙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翩概。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牲距。...
    茶點(diǎn)故事閱讀 40,567評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钥庇,靈堂內(nèi)的尸體忽然破棺而出牍鞠,到底是詐尸還是另有隱情,我是刑警寧澤评姨,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布难述,位于F島的核電站,受9級特大地震影響吐句,放射性物質(zhì)發(fā)生泄漏胁后。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一嗦枢、第九天 我趴在偏房一處隱蔽的房頂上張望攀芯。 院中可真熱鬧,春花似錦文虏、人聲如沸侣诺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽紧武。三九已至,卻和暖如春敏储,著一層夾襖步出監(jiān)牢的瞬間阻星,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工已添, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妥箕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓更舞,卻偏偏與公主長得像畦幢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子缆蝉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理宇葱,服務(wù)發(fā)現(xiàn)瘦真,斷路器,智...
    卡卡羅2017閱讀 134,702評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,859評論 6 342
  • 核心概念 Repository Repository 是Spring Data 的核心接口 黍瞧。 它將domai...
    金剛_30bf閱讀 7,597評論 0 2
  • 他們說诸尽,你不會回來了 說你落在一個(gè)遙遠(yuǎn)的海里 像一條魚一樣 永遠(yuǎn)在那里呼吸 他們說,你不會回來了 說你穿過白茫茫的...
    悅木君閱讀 260評論 0 0
  • 群主鄙人@洛一夫印颤,洛陽一農(nóng)夫您机,即@田軍一員是也。@山水秀故年局,@天生美麗际看,無數(shù)次@A小語,@玉如意也矢否,其樂陶陶! @...
    金垛愚叟閱讀 543評論 1 1