搶佔先機
VMware 提供培訓和認證,助您加速前進。
瞭解更多Spring Data JPA 允許使用 @Query
註解手動定義由 Repository 方法執行的查詢。遺憾的是,JPQL 中的引數繫結相當有限,只允許設定值並提供一些型別轉換。Evans 釋出列車的最新 Spring Data JPA M1 版本透過新增 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,並使用它們準備用於評估 @Query
中定義的 SpEL 表示式的 EvaluationContext
。
到位的擴充套件現在將讓您充分利用 Spring Security SpEL 函式的全部功能。想象一個 Repository 查詢方法,它應返回當前使用者擁有的 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 Repository 中找到此處所示程式碼片段的實際示例。
新特性常常能實現以前認為不可能的事情——例如在原生查詢中進行分頁。由於該機制也暴露了 Sort
或 Pageable
等特殊引數型別,我們現在可以在原生查詢中使用分頁。相關示例可以在這裡找到 UserRepository。
目前我們正在研究將 Spring Security 更緊密地整合到 Spring Data 中。我們還在努力為其他 Spring Data 模組新增 SpEL 功能支援。
現在輪到您了——請在下方評論中告訴我們您的想法,或者在我們的 JIRA 中提交功能請求。
SpringOne 2GX 2014 臨近了。
如果您想了解更多關於 Spring Data 的資訊,請務必註冊參加今年的 SpringOne 大會。日程表中包含許多與資料相關的講座,將向您介紹 Evans 版本即將釋出的新特性。