Object-Directory Mapping (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)

Annotations

使用对象映射方法管理的实体类需要使用 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 标注还可以将实体字段映射到条目的专有名称的组件。只有 String 类型的字段才能使用 @DnAttribute 标注。不支持其他类型。

当指定类中所有 @DnAttribute 注解的 index 属性时,在创建和更新条目时也可以自动计算 DN。对于更新场景,如果与识别名称相关联的属性发生更改,这还会自动在树中移动条目。

记住所有字段都默认映射到 LDAP 属性。@DnAttribute 不会更改此设置;换句话说,除非您还用 @Transient 注解字段,否则用 @DnAttribute 注解的字段也将映射到 LDAP 属性。

Execution

当所有组件都已正确配置并进行标注时,可以使用 LdapTemplate 的对象映射方法,如下所示:

Example 1. Execution
@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 and Distinguished Names as Attribute Values

LDAP 中的安全组通常包含一个多值属性,其中每个值都是系统中用户的 distinguished name。有关处理此类属性时的困难已在 xref:dirobjectfactory.adoc#dns-as-attribute-values[DirContextAdapter 和 Distinguished Names as Attribute Values 中进行了解释。

ODM 还支持 javax.naming.Name 属性值,这使得组修改变得容易,如下例所示:

Example 2. Example Group representation
@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);
    }
}

当您使用 setMembersaddMemberremoveMember 修改组成员,然后调用 ldapTemplate.update() 时,属性修改是通过使用专有名称相等性计算的,这意味着在计算它们是否相等时不考虑专有名称的文本格式。