領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多Spring Data JPA 允許使用 @Query 註解手動定義要由儲存庫方法執行的查詢。不幸的是,JPQL 中的引數繫結非常有限,只允許您設定一個值並提供一些型別轉換。最新的 Spring Data JPA M1 Evans 釋出列車版本透過新增對使用 SpEL 表示式在 @Query 註解的語句中動態繫結引數的支援,減輕了這種痛苦,這在手動定義查詢時提供了額外的靈活性。在這篇博文中,我將向您介紹此功能的功能。
SpEL 支援提供對查詢方法引數的訪問。這允許您直接繫結引數,或在繫結之前執行額外的操作。
@Query("select u from User u where u.age = ?#{[0]}")
List<User> findUsersByAge(int age);
@Query("select u from User u where u.firstname = :#{#customer.firstname}")
List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);
引數透過索引訪問(在第一個方法中為 [0])或透過使用 @Param 宣告的名稱公開。實際的 SpEL 表示式繫結由 ?# 或 :# 觸發。我們支援這兩種型別,以便您可以與查詢定義中也可能出現的標準 JPQL 引數繫結保持一致。特殊型別的引數,如 Sort 和 Pageable,以其簡單的類名作為變數公開。
雖然高階引數繫結是一個非常有用的特性,但 SpEL 的真正強大之處在於,表示式可以引用框架抽象或其他應用程式元件。SpEL 的一個非常常見的場景是定義安全約束。因此,如果我們能將查詢限制為只返回與當前認證使用者相關的結果,那就太酷了。
@Query("select u from User u where u.emailAddress = ?#{principal.emailAddress}")
List<User> findCurrentUserWithCustomQuery();
正如您所看到的,我們引用了 Spring Security 的 principal 的一個屬性。那麼 Spring Data SpEL 支援如何與 Spring Security 整合呢?
Spring Data 暴露了一個擴充套件點 EvaluationContextExtension。該介面允許實現者以非常詳細的方式自定義 EvaluationContext,但為了方便,我們提供了一個 EvaluationContextExtensionSupport 基類,讓您可以方便地只實現您感興趣的部分。
class SecurityEvaluationContextExtension extends EvaluationContextExtensionSupport {
@Override
public String getExtensionId() {
return "security";
}
@Override
public SecurityExpressionRoot getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {};
}
}
對於我們的 Spring Security 擴充套件,我們擴充套件了 EvaluationContextExtensionSupport 並重寫了 getRootObject() 方法,返回一個新的 SecurityExpressionRoot 例項,該例項公開了您已經從 @PreAuthorize 的使用中瞭解到的所有安全屬性和表示式。此步驟還使它們在我們的 @Query 註解的 SpEL 表示式中可用。
我們需要採取的最後一步是將安全擴充套件註冊為一個 bean。
@Configuration
@EnableJpaRepositories
class SecurityConfiguration {
@Bean
EvaluationContextExtension securityExtension() {
return new SecurityEvaluationContextExtension();
}
}
Spring Data JPA 將會獲取所有 EvaluationContextExtension 型別的 bean,並使用它們來準備 EvaluationContext,以便評估 @Query 中定義的 SpEL 表示式。
現在,透過此擴充套件,您可以充分利用 Spring Security SpEL 函式的強大功能。想象一個倉庫查詢方法,它應該返回當前使用者擁有的 BusinessObject,如果當前使用者是管理員,則返回所有 BusinessObject。查詢方法的定義將如下所示:
interface SecureBusinessObjectRepository extends Repository<BusinessObject,Long>{
@Query("select o from BusinessObject o where o.owner.emailAddress like "+
"?#{hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress}")
List<BusinessObject> findBusinessObjectsForCurrentUser();
}
您可以在 Spring-Data-Examples 倉庫中找到此處所示程式碼片段的執行示例。
通常,新功能能夠實現以前認為不可能的事情——一個例子就是原生查詢中的分頁。由於這種機制也暴露了 Sort 或 Pageable 等特殊引數型別,我們現在能夠在原生查詢中使用分頁。一個例子可以在 UserRepository 中找到。
目前我們正在研究將 Spring Security 更緊密地整合到 Spring Data 中。我們還在努力為其他 Spring Data 模組新增 SpEL 功能支援。
現在輪到你了——請在下面的評論中告訴我們你的想法,或者在我們的 JIRA 中提交功能請求。
SpringOne 2GX 2014 即將舉行。
如果您想了解更多關於 Spring Data 的資訊,請務必註冊參加今年的 SpringOne 大會。日程表包含許多與資料相關的講座,旨在向您介紹我們將隨 Evans 一起釋出的最新功能。