物件-目錄對映 (ODM)

物件關係對映框架(如 Hibernate 和 JPA)為開發者提供了使用註解將關係資料庫表對映到 Java 物件的能力。Spring LDAP 專案在 LDAP 目錄方面也提供了類似的能力,透過 LdapOperations 中的多種方法實現。

  • <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)

註解

使用物件對映方法管理的實體類需要使用 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 註解將條目的 distinguished name 對映到一個欄位。該欄位必須是 javax.naming.Name 的例項。

其次,@Attribute 註解將實體欄位對映到 LDAP 屬性。當屬性名稱與欄位名稱不同時,這非常有用。要使用 @Attribute,您必須宣告欄位對映到的屬性名稱。可選地,您還可以透過包含 LDAP 屬性的語法 OID 來保證精確匹配。最後,@Attribute 還提供了型別宣告,允許您指示屬性是被 LDAP JNDI 提供者視為二進位制還是基於字串的。

第三,@Transient 註解指示給定的實體欄位不對映到 LDAP 屬性。

最後,@DnAttribute 註解還將實體欄位對映到條目 distinguished name 的組成部分。

考慮一個帶有以下註解的類

@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。對於更新場景,如果作為 distinguished name 一部分的屬性已更改,這也會自動處理條目在樹中的移動。

Note that while both attributes are present on `@DnAttribute`, if `index` is specified, then `name` is ignored.
請記住,預設情況下所有欄位都對映到 LDAP 屬性。@DnAttribute 不會改變這一點;換句話說,用 @DnAttribute 註解的欄位也將對映到 LDAP 屬性,除非您也用 @Transient 註解該欄位。

執行

當所有元件都已正確配置和註解後,可以使用 LdapTemplate 的物件對映方法,如下所示

示例 1. 執行
@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 和作為屬性值的 Distinguished Name

LDAP 中的安全組通常包含一個多值屬性,其中每個值都是系統中使用者的 distinguished name。在處理此類屬性時涉及的困難已在 DirContextAdapter 和作為屬性值的 Distinguished Name 中討論。

ODM 也支援 javax.naming.Name 屬性值,使得組修改變得容易,如下例所示

示例 2. 組表示示例
@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() 時,屬性修改是使用 distinguished name 相等性來計算的,這意味著在判斷它們是否相等時,會忽略 distinguished name 的文字格式。