查询方法

你在仓库上触发的大多数数据访问操作通常都会导致对 LDAP 目录执行查询。 定义这样的查询只需在仓库接口中声明一个方法,如下例所示:spring-doc.cadn.net.cn

带有查询方法的 PersonRepository
interface PersonRepository extends PagingAndSortingRepository<Person, String> {

    List<Person> findByLastname(String lastname);                            (1)

    List<Person> findByLastnameFirstname(String lastname, String firstname); (2)
}
1 该方法展示了查询所有具有指定 lastname 的人员。 查询语句是通过解析方法名称中的约束条件生成的,这些约束条件可以用 AndOr 连接起来。 因此,该方法名会生成一个查询表达式:(&(objectclass=person)(lastname=lastname))
2 该方法展示了查询所有具有指定 lastnamefirstname 的人员。 该查询是通过解析方法名称派生而来的。 因此,该方法名称会生成一个查询表达式:(&(objectclass=person)(lastname=lastname)(firstname=firstname))

下表提供了可在查询方法中使用的关键词示例:spring-doc.cadn.net.cn

表1. 查询方法支持的关键字
关键字 示例 逻辑结果

LessThanEqualspring-doc.cadn.net.cn

findByAgeLessThanEqual(int age)spring-doc.cadn.net.cn

(attribute⇐age)spring-doc.cadn.net.cn

GreaterThanEqualspring-doc.cadn.net.cn

findByAgeGreaterThanEqual(int age)spring-doc.cadn.net.cn

(attribute>=age)spring-doc.cadn.net.cn

IsNotNull, NotNullspring-doc.cadn.net.cn

findByFirstnameNotNull()spring-doc.cadn.net.cn

(firstname=*)spring-doc.cadn.net.cn

IsNull, Nullspring-doc.cadn.net.cn

findByFirstnameNull()spring-doc.cadn.net.cn

(!(firstname=*))spring-doc.cadn.net.cn

Likespring-doc.cadn.net.cn

findByFirstnameLike(String name)spring-doc.cadn.net.cn

(firstname=name)spring-doc.cadn.net.cn

NotLike, IsNotLikespring-doc.cadn.net.cn

findByFirstnameNotLike(String name)spring-doc.cadn.net.cn

(!(firstname=name*))spring-doc.cadn.net.cn

StartingWithspring-doc.cadn.net.cn

findByStartingWith(String name)spring-doc.cadn.net.cn

(firstname=name*)spring-doc.cadn.net.cn

EndingWithspring-doc.cadn.net.cn

findByFirstnameLike(String name)spring-doc.cadn.net.cn

(firstname=*name)spring-doc.cadn.net.cn

Containingspring-doc.cadn.net.cn

findByFirstnameLike(String name)spring-doc.cadn.net.cn

(firstname=*name*)spring-doc.cadn.net.cn

(No keyword)spring-doc.cadn.net.cn

findByFirstname(String name)spring-doc.cadn.net.cn

(Firstname=name)spring-doc.cadn.net.cn

Notspring-doc.cadn.net.cn

findByFirstnameNot(String name)spring-doc.cadn.net.cn

(!(Firstname=name))spring-doc.cadn.net.cn

使用@Query

如果需要使用无法从方法名派生的自定义查询,可以使用 @Query 注解来定义该查询。 由于查询与执行它们的 Java 方法相关联,因此实际上可以将参数绑定并传递给查询。spring-doc.cadn.net.cn

以下示例展示了一个使用 @Query 注解创建的查询:spring-doc.cadn.net.cn

示例 1. 在查询方法中使用 @Query 声明查询
interface PersonRepository extends LdapRepository<Person, Long> {

  @Query("(&(employmentType=*)(!(employmentType=Hired))(mail=:emailAddress))")
  Person findEmployeeByEmailAddress(String emailAddress);

}
Spring Data 支持命名参数(参数名以 : 为前缀)和位置参数绑定(形式为从零开始的 ?0)。 我们建议使用命名参数,以提高可读性。 此外,在重构时,如果参数位置发生变化,使用位置参数会使查询方法更容易出错。

参数编码

基于字符串的查询的参数根据 RFC2254 进行编码。 这可能导致某些字符被不需要的转义。 您可以通过 @LdapEncode 注解指定自定义编码器,该注解定义了要使用的 LdapEncoderspring-doc.cadn.net.cn

@LdapEncode 应用于查询方法的单个参数。 它不适用于派生查询或值表达式(SpEL、属性占位符)。spring-doc.cadn.net.cn

示例 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 值表达式(Value Expressions)支持的一部分。 SpEL 表达式可用于操作查询方法的参数,也可用于调用 Bean 的方法。 方法参数可以通过名称或索引进行访问,如下例所示。spring-doc.cadn.net.cn

示例 3. 在 Repository 查询方法中使用 SpEL 表达式
@Query("(&(firstName=?#{[0]})(mail=:?#{principal.emailAddress}))")
List<Person> findByFirstnameAndCurrentUserWithCustomQuery(String firstname);
通过 SpEL 表达式提供的值不会根据 RFC2254 进行转义。 如有需要,您必须确保这些值已正确转义。 建议使用 Spring LDAP 的 org.springframework.ldap.support.LdapEncoder 辅助类。

使用属性占位符

属性占位符(参见值表达式)可根据 Spring Environment 中的配置属性,轻松地自定义您的查询。 这对于需要根据环境或配置进行定制的查询非常有用。spring-doc.cadn.net.cn

示例 4. 在 Repository 查询方法中使用属性占位符
@Query("(&(firstName=?0)(stage=:?${myapp.stage:dev}))")
List<Person> findByFirstnameAndStageWithCustomQuery(String firstname);
属性占位符(Property Placeholders)所提供的值不会根据 RFC2254 进行转义。 如有需要,您必须确保这些值已被正确转义。 建议使用 Spring LDAP 提供的 org.springframework.ldap.support.LdapEncoder 辅助类。