天天看點

Jmix 的資料通路層:将 JPA 用到極緻

Jmix 的資料通路層:将 JPA 用到極緻

      對任何企業及應用來說,資料模型都是應用的基石之一。在設計資料模型時,除了需要考慮業務資料的要求之外,還應該思考一些有可能會影響應用程式設計的問題。比如,是否需要資料庫表行級的安全機制?是否需要使用軟删除?是否需要 crud api,如果需要的話,誰來幹這個枯燥的活?

      事實上,jpa 已經是 java 應用程式中建立資料模型的标準了。但是 jpa 不提供能實作進階安全機制的接口,也沒有軟删除,是以有需求的程式員隻能自己實作。

      jmix 架構提供了通用的引擎,可以為使用 jpa 的應用程式增加額外的功能。在不破壞 jpa 相容性的情況下,jmix 架構可以讓您愉快的使用進階資料安全機制,無感的使用軟删除,并且為 crud 操作提供通用 rest api 以及其他的功能。

      本文将讨論 jmix 中的資料通路層,談談使用該架構及其工具到底能做什麼,還會讨論資料通路層的一些底層原理。

      對于熟悉 jpa 的 java 開發者來說,使用 jmix 不需要學習任何新的知識。隻需要建立 jpa 實體即可。jmix 也提供了可視化設計器可以幫助完成這一工作。

      在 jmix 的可視化設計器中,您需要提供實體名稱,選擇 id 類型(uuid、long、integer、string 或者嵌入類),然後選擇需要支援的功能:

實體版本 - 支援樂觀鎖

建立時審計 - 增加建立時間、建立人

更新時審計 - 增加更新時間、更新人

軟删除 - 增加删除時間、删除人

Jmix 的資料通路層:将 JPA 用到極緻

      最後,您會得到類似如下的 jpa 類:

      注意,jmix 并非侵入式的影響你的代碼。生成的實體隻是添加了一些注解,不需要實作任何架構特有的接口,更不需要繼承某個類。這樣的非侵入式設計,在實作您應用程式特有的實體關系和架構時,能保持足夠的靈活度以适應你的業務需求。

      jmix 使用的大部分注解要麼來自 jpa 要麼來自 spring boot jpa 庫:​<code>​@entity、@versioned、@createdby、@lastmodifiedby​</code>​,您之前也許都見過。jmix 架構依賴 spring boot 的具體實作來支援樂觀鎖以及建立和更新審計。

      下面看看資料模型中幾個 jmix 特有的注解:

​<code>​@jmixentity​</code>​ - 引導 jmix 資料通路層将此類添加至實體倉庫(entities repository)

​<code>​@jmixgeneratedvalue​</code>​ - 表示實體的 ​<code>​id​</code>​ 屬性必須由 jmix 生成并指定

​<code>​@deletedby​</code>​ 和 ​<code>​@deleteddate​</code>​ - 标記字段,當使用軟删除方案時用來标記實體的删除狀态

      您也許會問:“什麼是 jmix 資料通路層中的實體倉庫?你們是不是有自己的資料通路引擎?” 答案是也不是。jmix 架構會存儲應用程式資料模型的額外資訊 - metamodel(元模型),并且增加了一個特殊的工具 - ​<code>​datamanager​</code>​ - 用來通路資料,但是其底層還是用的 jpa。

      jmix 基于 spring boot 架構建構。boot 以廣泛使用 ioc 模式而聞名天下,該模式意味着将有關 bean 的所有資料存儲在特殊的存儲庫中 - ​<code>​applicationcontext​</code>​。除了這個存儲之外,jmix 将關于應用程式資料模型的所有資料(比如 metadata)存儲在另一個存儲庫中 - ​<code>​metadata​</code>​。

      jmix 中 ​<code>​metadata​</code>​ 是資料通路層的核心。包含關于實體、屬性、實體關系等等所有的資訊。這些資訊是在應用程式啟動時對類進行掃描的過程中一次收集的,jmix 用這些資訊來實作神奇的功能:從行級資料安全機制到自動生成的管理界面 ui 的雙向資料綁定。

      為了有效的使用 jmix 資料通路層,需要使用 datamanager 元件。該元件是 jpa 中著名 ​<code>​entitymanager​</code>​ 的包裝類。與 ​<code>​entitymanager​</code>​ 類似,​<code>​datamanager​</code>​ 能使用 jpql 查詢語句或者 id 加載實體,儲存或删除實體以及對所選執行個體進行計數。

      下面是 ​<code>​datamanager​</code>​ 的一些示例用法。

      通過 ​<code>​id​</code>​ 加載一個實體,使用 java 類作為參數:

      使用 jpql 查詢加載資料:

      ​<code>​datamanager​</code>​ 使用 ​<code>​metamodel​</code>​ 提供一些額外的功能。是這樣實作的:在對應用程式資料庫的請求交由 ​<code>​entitymanager​</code>​ 執行之前,對請求進行攔截并修改。

       我們仔細看看 jmix 提供的這些功能。

      首先需要提到的是 jmix 的資料本機安全性授權。架構使用基于角色的安全機制并定義了兩種類型的角色:

         1. 資源角色(resource role)- 授予通路實體對象并在系統中執行特定操作的權限:對實體,實體屬性進行 curd 操作,使用 ui 界面等等。

         2. 行級角色(row-level role)- 可以限制對表中特定資料行的通路,換句話說,即限制通路某些實體執行個體。

      下面是資源角色的示例,可以定義實體 crud 操作的政策,甚至可以定義針對實體屬性操作的政策:

      為了實作這個功能,​<code>​datamanager​</code>​ 會分析 jpql,然後依據政策的定義限制該 jpql 的執行或修改 jpql 中的屬性清單以符合安全政策。

      如需定義行級角色,您需要制定一個 jpql 政策,該 jqpl 政策由 ​<code>​where​</code>​ 以及可選的 ​<code>​join​</code>​ 子句組成,用來限制從資料庫表中選取的資料:

      是以,帶有行級角色使用者發起的所有查詢都會通過這種方式進行轉換:​<code>​where​</code>​子句會用 and 操作符添加在現有的條件之後,​<code>​join​</code>​ 子句也會添加在現有的之後。如果 jpql 中沒有這兩個關鍵字,相應的子句會直接添加在後面。

      ​<code>​metadata​</code>​ 存儲庫在這裡扮演了重要的角色。它能幫助我們正确的解析并修改 jpql 并能找出受限的屬性和實體,無論使用的是 jpql 還是 java 類來定義 db 查詢。

      某些情況下,有必要在企業級應用中使用軟删除。我們釋出了 cuba 部落格“是否實施軟删除,這是個問題!” 專門讨論了軟删除模式的優缺點。jmix 是下一代 cuba,是以也支援軟删除。

      如果實體中有 ​<code>​@deletedby​</code>​ 和 ​<code>​@deleteddate​</code>​ 注解的字段,則該實體會自動啟用軟删除模式。對于這些實體,所有 ​<code>​datamanager​</code>​ 中調用的 ​<code>​remove()​</code>​ 都會被轉換成 ​<code>​update​</code>​ 語句,而所有的 ​<code>​find()​</code>​ 請求都會被修改,添加一個合适的 ​<code>​where​</code>​ 子句用來過濾那些被 “删除” 的實體。

      這裡我們需要 ​<code>​metadata​</code>​ 來找出哪一列需要更新或者添加到 where 子句中。與 cuba 不同,jmix 不要求實體實作一個特定的接口才能支援軟删除。而隻需要将兩個注解添加至實體的兩個字段即可。

      盡管我們用了軟删除,但是資料并沒有删掉,是以您還是可以使用 “硬删除”,如果想看到軟删除的資料,可以使用 jpa 的 ​<code>​entitymanager​</code>​ 和原生 sql 查詢。

      自動建立 crud api 是 jmix metamodel 的亮點。當您擁有應用程式中所有實體的資訊時,建立實體操作的 api 就非常容易了。

      比如,如果有資料模型的中繼資料,那麼處理下面這個 http 請求将不是難事:

      比如,crud 操作的 endpoints 清單是這樣的:

Jmix 的資料通路層:将 JPA 用到極緻

      使用 jmix 的好處就是您不需要手動實作這些枯燥的 endpoints。由于有 metamodel,所有這些都能自動生成。在開發 “為前端服務的後端” 時,可以從自動生成的代碼開始逐漸建構您自己的特定 rest api。

      如果您的要求比通用 crud rest api 更靈活,可以使用 graphql。graphql 的一個核心概念就是 schema。使用 jmix 的 metamodel,我們毫不費力就能獲得 graphql schema 所需的所有資料。

      也就是說,jmix 應用程式使用 graphql api 是和 rest api 類似,能以通用的方式實作(很快将釋出)。是以,在您的 jmix 應用程式中添加 graphql endpoint,隻需在建構腳本中簡單增加一個 starter 即可:

      然後就可以使用類似這樣的查詢了:

      隻需在 jmix 中使用熟悉的 jpa 注解定義資料模型,您就能建立一個可用的應用程式。借助 jmix 的 metamodel,無需進行額外的編碼即可使用下列功能:

          1. 行級安全機制

          2. 軟删除

          3. crud rest api

          4. graphql api

      如您所見,使用 jmix 建立一個簡單的以資料為中心的應用程式,并帶有進階功能和管理界面将變得非常容易。