这个版本仍在开发中,目前尚未被认为是稳定的。要使用最新稳定版本,请使用 Spring LDAP 4.0.2spring-doc.cadn.net.cn

对象-目录映射 (ODM)

对象关系映射框架(如 Hibernate 和 JPA)使开发人员能够使用注解将关系型数据库表映射到 Java 对象。 Spring LDAP 项目通过 LdapOperations 中的多种方法提供类似的映射能力。spring-doc.cadn.net.cn

配置

LdapTemplate 构造一个默认的 ObjectDirectoryMapper,通常会使得额外的配置变得不必要。spring-doc.cadn.net.cn

转换器与 Boot

ObjectDirectoryMapper 支持 ConversionService,它允许你指定 Converter 以在 Java 和 LDAP 之间进行映射。spring-doc.cadn.net.cn

当您使用 Spring Boot 时,您可以像平常一样发布一个 Converter,而 Boot 提供的 ObjectDirectoryMapper 个豆将拾取它们。spring-doc.cadn.net.cn

转换器不使用 Boot

你也可以通过导入ObjectDirectoryMapperConfiguration,将ObjectDirectoryMapper也作为@Bean使用:spring-doc.cadn.net.cn

@Import(ObjectDirectoryMapperConfiguration.class)
@Configuration
public class LdapConfig {
	// ...
}

然后你可以将其提供给你的LdapTemplate实例,如下所示:spring-doc.cadn.net.cn

@Bean
LdapTemplate ldapTemplate(ContextSource contextSource, ObjectDirectoryMapper odm) {
	LdapTemplate ldap = new LdapTemplate(contextSource);
	ldap.setObjectDirectoryMapper(odm);
	return ldap;
}

这样做将使得Spring LDAP会使用您配置的Converter个实例。spring-doc.cadn.net.cn

注解

实体类在使用对象映射方法进行管理时,必须使用来自org.springframework.ldap.odm.annotations包的注解进行注解。可用的注解有:spring-doc.cadn.net.cn

@Entry@Id 注解必须在受管类上声明。 @Entry 用于指定该实体映射的对象类,并可选地指定由该类表示的LDAP条目的目录根。 对于所有具有字段映射的对象类都必须声明。请注意,当创建受管类的新条目时,只使用声明的对象类。spring-doc.cadn.net.cn

为了将目录条目视为与受管理实体匹配,该目录条目声明的所有对象类必须由@Entry注解声明。 例如,假设你的LDAP树中有以下对象类:inetOrgPerson,organizationalPerson,person,top。 如果你只想修改person对象类中定义的属性,你可以用@Entry注解@Entry(objectClasses = { "person", "top" })。 但是,如果你想要管理inetOrgPerson对象类中定义的属性,就需要使用以下内容:@Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })spring-doc.cadn.net.cn

所有实体字段都按照字段名映射到LDAP属性。其余注解 — @Id, @Attribute, @Transient, 和 @DnAttribute — 会影响该映射方式。spring-doc.cadn.net.cn

首先,@Id 注解将条目的区分名称映射到一个字段。该字段必须是 javax.naming.Name 的实例。spring-doc.cadn.net.cn

第二,@Attribute 注解将实体字段映射到 LDAP 属性。 当属性名称与字段名称不同时,此功能非常 handy。 要使用 @Attribute,必须声明字段映射的属性名称。 可选地,还可以通过包含 LDAP 属性的语法 OID 来保证精确匹配。 最后,@Attribute 也提供类型声明,让你能够指示该属性由 LDAP JNDI 提供程序视为二进制或字符串类型。spring-doc.cadn.net.cn

第三,@Transient 注解表示给定的实体字段不映射到一个 LDAP 属性。spring-doc.cadn.net.cn

最后,@DnAttribute 注解还将其映射到条目 distinguished name 的组件。spring-doc.cadn.net.cn

考虑一个带有以下注解的类:spring-doc.cadn.net.cn

@DnAttribute(name="uid")
String uid;

并且一个如下所示的DN:spring-doc.cadn.net.cn

uid=carla,dc=springframework,dc=org

那么Spring LDAP将使用uid=carla来填充uid,而不是查找uid属性。spring-doc.cadn.net.cn

Only fields of type `String` can be annotated with `@DnAttribute`. Other types are not supported.

您可以选择性地提供一个索引,例如如下所示:spring-doc.cadn.net.cn

@DnAttribute(index=1)
String uid;

@DnAttribute(index=0)
String department;

这对于具有多个组件的DNs来说很方便:spring-doc.cadn.net.cn

uid=carla,department=engineering,dc=springframework,dc=org

使用一个index也可以让Spring LDAP在创建或定位实体进行更新或删除时,自动计算DN。 在更新场景中,这还会自动处理当构成区分名称的属性发生变化时的树状条目移动。spring-doc.cadn.net.cn

Note that while both attributes are present on `@DnAttribute`, if `index` is specified, then `name` is ignored.
记得所有字段默认都会映射到LDAP属性。 @DnAttribute 并不会改变这一点;换句话说,标注为 @DnAttribute 的字段也会映射到LDAP属性,除非你同时给该字段标注了 @Transient

执行

当所有组件都已正确配置和注解时,LdapTemplate 的对象映射方法可以如下使用:spring-doc.cadn.net.cn

示例 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 和 区分名称 作为 属性 值

在基于LDAP的安全组中,通常包含一个多值属性,其中每个值都是系统中用户的区分名称。 处理此类属性时遇到的困难在DirContextAdapter和作为属性值的区分名称中进行了讨论。spring-doc.cadn.net.cn

ODM还支持javax.naming.Name属性值,使得分组修改变得容易,如下例所示:spring-doc.cadn.net.cn

示例 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() 时, 属性修改通过区分名称等值性进行计算,这意味着在判断它们是否相等时会忽略区分名称的文本格式。spring-doc.cadn.net.cn