Query Methods
你在仓储上通常触发的数据访问操作中的大多数都会导致针对 LDAP 目录运行一个查询。定义这样一个查询只需在仓储接口上声明一个方法即可,如下例所示:
interface PersonRepository extends PagingAndSortingRepository<Person, String> {
List<Person> findByLastname(String lastname); 1
List<Person> findByLastnameFirstname(String lastname, String firstname); 2
}
该方法显示查询所有具有给定
lastname的人员。该查询通过解析方法名称推导得出,其中可以包含可用And和Or连接的条件。因此,方法名称生成的查询表达式为(&(objectclass=person)(lastname=lastname))。该方法显示查询所有具有给定
lastname和firstname的人员。该查询通过解析方法名称推导得出。因此,方法名称生成的查询表达式为(&(objectclass=person)(lastname=lastname)(firstname=firstname))。
下表提供了你可以与查询方法一起使用的关键字示例:
表 1. 查询方法支持的关键字
| 关键字 | 示例 | 逻辑结果 |
|---|---|---|
LessThanEqual | findByAgeLessThanEqual(int age) | (attribute⇐age) |
GreaterThanEqual | findByAgeGreaterThanEqual(int age) | (attribute>=age) |
IsNotNull, NotNull | findByFirstnameNotNull() | (firstname=*) |
IsNull, Null | findByFirstnameNull() | (!(firstname=*)) |
Like | findByFirstnameLike(String name) | (firstname=name) |
NotLike, IsNotLike | findByFirstnameNotLike(String name) | (!(firstname=name*)) |
StartingWith | findByStartingWith(String name) | (firstname=name*) |
EndingWith | findByFirstnameLike(String name) | (firstname=*name) |
Containing | findByFirstnameLike(String name) | (firstname=*name*) |
(No keyword) | findByFirstname(String name) | (Firstname=name) |
Not | findByFirstnameNot(String name) | (!(Firstname=name)) |
使用 @Query
如果你需要使用无法从方法名推导的自定义查询,可以使用 @Query 注解来定义查询。由于查询与运行它的 Java 方法绑定,因此实际上可以将参数绑定并传递给查询。
以下示例展示了使用 @Query 注解创建的查询:
示例 1. 在查询方法中使用 @Query 声明查询
interface PersonRepository extends LdapRepository<Person, Long> {
@Query("(&(employmentType=*)(!(employmentType=Hired))(mail=:emailAddress))")
Person findEmployeeByEmailAddress(String emailAddress);
}
Spring Data 支持命名参数(参数名前缀为 :)和位置参数绑定(形式为从 0 开始的 ?0)。我们建议使用命名参数以提高可读性。此外,在重构涉及参数位置时,使用位置参数会使查询方法更容易出错。
参数编码
基于字符串的查询的查询参数会根据 RFC 2254 进行编码。这可能导致某些字符被意外转义。你可以通过 @LdapEncode 注解指定自己的编码器,该注解定义了要使用的 LdapEncoder。
@LdapEncode 适用于查询方法的各个参数。它不适用于派生查询或值表达式(SpEL、Property Placeholders)。
示例 2. 为查询方法声明自定义 LdapEncoder
interface PersonRepository extends LdapRepository<Person, Long> {
@Query("(&(employmentType=*)(!(employmentType=Hired))(firstName=:firstName))")
Person findEmployeeByFirstNameLike(@LdapEncode(MyLikeEncoder.class) String firstName);
}
使用 SpEL 表达式
Spring Data 允许你在查询方法中使用 SpEL 表达式。SpEL 表达式是 Spring Data’s Value Expressions 支持的一部分。SpEL 表达式可用于操作查询方法参数以及调用 bean 方法。方法参数可以通过名称或索引访问,如下例所示。
示例 3. 在 Repository Query Methods 中使用 SpEL 表达式
@Query("(&(firstName=?#{[0]})(mail=:?#{principal.emailAddress}))")
List<Person> findByFirstnameAndCurrentUserWithCustomQuery(String firstname);
由 SpEL 表达式提供的值不会按照 RFC2254 进行转义。如有需要,你必须确保这些值被正确转义。可以考虑使用 Spring Ldap 的 org.springframework.ldap.support.LdapEncoder 辅助类。
使用属性占位符
Property Placeholders(参见 值表达式)可帮助您根据来自 Spring’s Environment 的配置属性轻松自定义查询。这些占位符适用于需要根据环境或配置进行自定义的查询。
示例 4. 在 Repository Query Methods 中使用 Property Placeholders
@Query("(&(firstName=?0)(stage=:?${myapp.stage:dev}))")
List<Person> findByFirstnameAndStageWithCustomQuery(String firstname);
由 Property Placeholders 提供的值不会按照 RFC2254 进行转义。如果必要,你需要确保这些值已正确转义。可以考虑使用 Spring Ldap’s org.springframework.ldap.support.LdapEncoder 辅助类。