|
这个版本仍在开发中,目前尚未被认为是稳定的。要使用最新稳定版本,请使用 Spring LDAP 4.0.2! |
对象-目录映射 (ODM)
对象关系映射框架(如 Hibernate 和 JPA)使开发人员能够使用注解将关系型数据库表映射到 Java 对象。
Spring 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)
配置
LdapTemplate 构造一个默认的 ObjectDirectoryMapper,通常会使得额外的配置变得不必要。
转换器与 Boot
ObjectDirectoryMapper 支持 ConversionService,它允许你指定 Converter 以在 Java 和 LDAP 之间进行映射。
当您使用 Spring Boot 时,您可以像平常一样发布一个 Converter,而 Boot 提供的 ObjectDirectoryMapper 个豆将拾取它们。
转换器不使用 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注解@Entry(objectClasses = { "person", "top" })。
但是,如果你想要管理inetOrgPerson对象类中定义的属性,就需要使用以下内容:@Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })。
所有实体字段都按照字段名映射到LDAP属性。其余注解 — @Id, @Attribute, @Transient, 和 @DnAttribute — 会影响该映射方式。
首先,@Id 注解将条目的区分名称映射到一个字段。该字段必须是 javax.naming.Name 的实例。
第二,@Attribute 注解将实体字段映射到 LDAP 属性。
当属性名称与字段名称不同时,此功能非常 handy。
要使用 @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;
这对于具有多个组件的DNs来说很方便:
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() 时,
属性修改通过区分名称等值性进行计算,这意味着在判断它们是否相等时会忽略区分名称的文本格式。