对象目录映射 (ODM)
对象关系映射框架(如 Hibernate 和 JPA)使开发人员能够使用注解将关系数据库表映射到 Java 对象。Spring LDAP 项目通过 LdapOperations 中的许多方法提供了类似的 LDAP 目录映射能力
-
<T> T findByDn(Name dn, Class<T> clazz) -
<T> T findOne(LdapQuery query, Class<T> clazz) -
<T> List<T> find(LdapQuery query, Class<T> clazz) -
<T> List<T> findAll(Class<T> clazz) -
<T> List<T> findAll(Name base, SearchControls searchControls, Class<T> clazz) -
<T> List<T> findAll(Name base, Filter filter, SearchControls searchControls, Class<T> clazz) -
void create(Object entry) -
void update(Object entry) -
void delete(Object entry)
配置
LdapTemplate 构造了一个默认的 ObjectDirectoryMapper,通常无需额外配置。
使用 Boot 的转换器
ObjectDirectoryMapper 支持 ConversionService,它允许您指定自定义 Converter 用于 Java 和 LDAP 之间的映射。
当您使用 Spring Boot 时,您可以像往常一样发布一个 Converter,Boot 提供的 ObjectDirectoryMapper bean 将会识别它们。
不使用 Boot 的转换器
您还可以通过导入 ObjectDirectoryMapperConfiguration 来将 ObjectDirectoryMapper 作为 @Bean 提供,如下所示
@Import(ObjectDirectoryMapperConfiguration.class)
@Configuration
public class LdapConfig {
// ...
}
然后您可以将其提供给您的 LdapTemplate 实例,如下所示
@Bean
LdapTemplate ldapTemplate(ContextSource contextSource, ObjectDirectoryMapper odm) {
LdapTemplate ldap = new LdapTemplate(contextSource);
ldap.setObjectDirectoryMapper(odm);
return ldap;
}
这样做将使 Spring LDAP 使用您配置的 Converter 实例。
注解
使用对象映射方法管理的实体类需要使用 org.springframework.ldap.odm.annotations 包中的注解进行标注。可用的注解有
-
@Entry:类级别注解,指示实体映射到的objectClass定义。(必填) -
@Id:指示实体 DN。声明此属性的字段必须是javax.naming.Name类的派生类。(必填) -
@Attribute:指示目录属性到对象类字段的映射。 -
@DnAttribute:指示 DN 属性到对象类字段的映射。 -
@Transient:指示该字段不持久化,应被OdmManager忽略。
@Entry 和 @Id 注解必须在托管类上声明。@Entry 用于指定实体映射到哪些对象类,以及(可选)由该类表示的 LDAP 条目的目录根。所有映射字段的对象类都必须声明。请注意,在创建托管类的新条目时,只使用已声明的对象类。
为了使目录条目被认为是与托管实体匹配,目录条目声明的所有对象类都必须由 @Entry 注解声明。例如,假设您的 LDAP 树中有具有以下对象类的条目:inetOrgPerson,organizationalPerson,person,top。如果您只对更改 person 对象类中定义的属性感兴趣,您可以用 @Entry(objectClasses = { "person", "top" }) 注解您的 @Entry。但是,如果您想管理 inetOrgPerson 对象类中定义的属性,则需要使用以下内容:@Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })。
所有实体字段都通过其字段名映射到 LDAP 属性。其余注解 — @Id、@Attribute、@Transient 和 @DnAttribute — 影响该映射的发生方式。
首先,@Id 注解将条目的专有名称映射到字段。该字段必须是 javax.naming.Name 的实例。
其次,@Attribute 注解将实体字段映射到 LDAP 属性。当属性名与字段名不同时,这非常方便。要使用 @Attribute,您必须声明字段映射到的属性名称。可选地,您还可以通过包含 LDAP 属性的语法 OID 来保证精确匹配。最后,@Attribute 还提供了类型声明,它允许您指示 LDAP JNDI 提供程序是将属性视为二进制还是基于字符串。
第三,@Transient 注解指示给定实体字段不映射到 LDAP 属性。
最后,@DnAttribute 注解还将实体字段映射到条目专有名称的组件。
考虑一个具有以下注解的类
@DnAttribute(name="uid")
String uid;
以及如下所示的 DN
uid=carla,dc=springframework,dc=org
那么 Spring LDAP 将使用 uid=carla 填充 uid,而不是寻找 uid 属性。
Only fields of type `String` can be annotated with `@DnAttribute`. Other types are not supported.
您也可以如下提供一个索引
@DnAttribute(index=1)
String uid;
@DnAttribute(index=0)
String department;
这对于具有多个组件的 DN 很有用
uid=carla,department=engineering,dc=springframework,dc=org
使用 index 还允许 Spring LDAP 在创建或定位实体进行更新或删除时为您计算 DN。对于更新场景,如果作为专有名称一部分的属性已更改,这还会自动处理树中条目的移动。
Note that while both attributes are present on `@DnAttribute`, if `index` is specified, then `name` is ignored.
请记住,默认情况下所有字段都映射到 LDAP 属性。@DnAttribute 不会改变这一点;换句话说,用 @DnAttribute 注解的字段也将映射到 LDAP 属性,除非您还用 @Transient 注解该字段。 |
执行
当所有组件都正确配置和注解后,LdapTemplate 的对象映射方法可以如下使用
@Entry(objectClasses = { "person", "top" }, base="ou=someOu")
public class Person {
@Id
private Name dn;
@Attribute(name="cn")
@DnAttribute(value="cn", index=1)
private String fullName;
// No @Attribute annotation means this will be bound to the LDAP attribute
// with the same value
private String description;
@DnAttribute(value="ou", index=0)
@Transient
private String company;
@Transient
private String someUnmappedField;
// ...more attributes below
}
public class OdmPersonRepo {
@Autowired
private LdapTemplate ldapTemplate;
public Person create(Person person) {
ldapTemplate.create(person);
return person;
}
public Person findByUid(String uid) {
return ldapTemplate.findOne(query().where("uid").is(uid), Person.class);
}
public void update(Person person) {
ldapTemplate.update(person);
}
public void delete(Person person) {
ldapTemplate.delete(person);
}
public List<Person> findAll() {
return ldapTemplate.findAll(Person.class);
}
public List<Person> findByLastName(String lastName) {
return ldapTemplate.find(query().where("sn").is(lastName), Person.class);
}
public Stream<Person> streamFindByLastName(String lastName) {
return ldapTemplate.findStream(query().where("sn").is(lastName), Person.class);
}
}
ODM 和作为属性值的专有名称
LDAP 中的安全组通常包含一个多值属性,其中每个值都是系统中用户的专有名称。处理这类属性的困难在 DirContextAdapter 和作为属性值的专有名称 中讨论。
ODM 也支持 javax.naming.Name 属性值,使得组修改变得容易,如下例所示
@Entry(objectClasses = {"top", "groupOfUniqueNames"}, base = "cn=groups")
public class Group {
@Id
private Name dn;
@Attribute(name="cn")
@DnAttribute("cn")
private String name;
@Attribute(name="uniqueMember")
private Set<Name> members;
public Name getDn() {
return dn;
}
public void setDn(Name dn) {
this.dn = dn;
}
public Set<Name> getMembers() {
return members;
}
public void setMembers(Set<Name> members) {
this.members = members;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addMember(Name member) {
members.add(member);
}
public void removeMember(Name member) {
members.remove(member);
}
}
当您通过使用 setMembers、addMember 和 removeMember 修改组成员,然后调用 ldapTemplate.update() 时,属性修改是使用专有名称相等性计算的,这意味着在判断它们是否相等时,专有名称的文本格式将被忽略。