第三章 通过DirContextAdapter进行简单的属性访问及操作
3.1介绍
一个鲜为人知的可能被低估的Java Ldap Api DirContextAdapter 可以去创建一个context,它被很少用的原因是实现它需要创建一个Dircontext实例,Spring Ldap弥补了它的不足:一个默认的DirContext实现称作DirContextAdapter,与之相对应的DirObjectFactory的实现称作DefaultDirObjectFactory,同时使用DefaultDirObjectFactory,DirContextAdapter将变得非常实用。
3.2 使用ContextMapper搜索和查找
通常DefaultDirObjectFactory是注册在ContextSource中,这意味着每当在Ldap树中发现Context,它的属性和唯一Dn将用于构建一个DirContextAdapter,这将使我们用
ContextMapper去转换查询到的值而不是AttributeMapper。
例 3.1 使用ContextMapper查询
packagecom.example.dao;
publicclassPersonDaoImplimplementsPersonDao{
...
privatestaticclassPersonContextMapperimplementsContextMapper{
publicObjectmapFromContext(Objectctx){
DirContextAdaptercontext=(DirContextAdapter)ctx;
Personp=newPerson();
p.setFullName(context.getStringAttribute("cn"));
p.setLastName(context.getStringAttribute("sn"));
p.setDescription(context.getStringAttribute("description"));
returnp;
}
}
publicPersonfindByPrimaryKey(
Stringname,Stringcompany,Stringcountry){
Namedn=buildDn(name,company,country);
returnldapTemplate.lookup(dn, newPersonContextMapper());
}
}
上面的代码展示了我们可以直接通过名字查找属性,而不需要Attributes 和 BasicAttribute ,这在我们面对多个属性值的时候非常有用。取得多属性通常我们要使用
NamingEnumeration循环,从attrbutes得到值。但是DirContextAdapter可以帮助我们做到这一点,使用getStringAttributes()或者getObjectAttributes()方法
例3.2 :使用getStringAttributes()取得属性的多个值
privatestaticclassPersonContextMapperimplementsContextMapper{
publicObjectmapFromContext(Objectctx){
DirContextAdaptercontext=(DirContextAdapter)ctx;
Personp=newPerson();
p.setFullName(context.getStringAttribute("cn"));
p.setLastName(context.getStringAttribute("sn"));
p.setDescription(context.getStringAttribute("description"));
//TheroleNamespropertyofPersonisanStringarray
p.setRoleNames(context.getStringAttributes("roleNames"));
returnp;
}
}
3.2.1.The AbstractContextMapper
SpringLDAP提供了一个ContextMapper的抽象类AbstractContextMapper,它将提供构建好的DirContexOperations参数,上面的PersonContextMapper可以重写如下:
例3.3 使用AbstractContextMapper
privatestaticclassPersonContextMapper extendsAbstractContextMapper {
publicObject doMapFromContext(DirContextOperationsctx){
Personp=newPerson();
p.setFullName(context.getStringAttribute("cn"));
p.setLastName(context.getStringAttribute("sn"));
p.setDescription(context.getStringAttribute("description"));
returnp;
}
}0
3.3使用DirContextAdapter绑定和修改
相对于提取数据,DirContextAdapter在绑定和修改数据时隐藏属性细节方面的效率更高
3.3.1 绑定
这是一个改进的创建方法,请对照2.4.1的实现方式
packagecom.example.dao;
publicclassPersonDaoImplimplementsPersonDao{
...
publicvoidcreate(Personp){
Namedn=buildDn(p);
DirContextAdaptercontext=newDirContextAdapter(dn);
context.setAttributeValues("objectclass",newString[]{"top","pers
context.setAttributeValue("cn",p.getFullname());
context.setAttributeValue("sn",p.getLastname());
context.setAttributeValue("description",p.getDescription());
ldapTemplate.bind(context);
}
}
注意,这里DirContextAdapter作为第二个参数绑定(?),没有第三个参数,没有使用任何attributes
另外注意的是setAttributeValues()方法参数ObjectClass有两个值,如同取属性值一样麻烦,构建多值属性是繁琐和冗长的,你可以使用setAttributeValues()一次性完成它。
3.3.2 修改
反绑定代码和例3.4 几乎相同,“Bindingusing DirContextAdapter” 除了需要重新绑定。正如我们看到的2.5.2 。更合理的方法是用ModificationItem包含你想要做的操作,这将由你来决定在LdapTree中要操作的数据,而且DirContextAdapter可以帮助你,DirContextAdapter可以更好保持修改的属性,下面示例展示了这一功能
例3.5 使用DirContextAdapter修改
packagecom.example.dao;
publicclassPersonDaoImplimplementsPersonDao{
...
publicvoidupdate(Personp){
Namedn=buildDn(p);
DirContextOperationscontext=ldapTemplate.lookupContext(dn);
context.setAttributeValues("objectclass",newString[]{"top","person"});
context.setAttributeValue("cn",p.getFullname());
context.setAttributeValue("sn",p.getLastname());
context.setAttributeValue("description",p.getDescription());
ldapTemplate.modifyAttributes(context);
}
}
当ldapTemplate.lookup()操作没有返回值时将返回一个DirContextAdapter实例,虽然返回了一个对象,但更好的方法是自动强制返回一个DirContextOperations
(DirContextAdapter的实现方法)
细心的读者可能看来我们的create 和update方法中存在着重复,如果在同一类中,可以提取为一个单独的方法
例3.6 用DirContextAdapter绑定和修改
packagecom.example.dao;
publicclassPersonDaoImplimplementsPersonDao{
privateLdapTemplateldapTemplate;
...
publicvoidcreate(Personp){
Namedn=buildDn(p);
DirContextAdaptercontext=newDirContextAdapter(dn);
mapToContext(p,context);
ldapTemplate.bind(context);
}
publicvoidupdate(Personp){
Namedn=buildDn(p);
DirContextOperationscontext=ldapTemplate.lookupContext(dn);
mapToContext(person,context);
ldapTemplate.modifyAttributes(context);
}
protectedvoidmapToContext(Personp,DirContextOperationscontext){
context.setAttributeValues("objectclass",newString[]{"top","person"});
context.setAttributeValue("cn",p.getFullName());
context.setAttributeValue("sn",p.getLastName());
context.setAttributeValue("description",p.getDescription());
}
}
3.4 一个完整的PersonDao类
例3.7
packagecom.example.dao;
importjava.util.List;
importjavax.naming.Name;
importjavax.naming.NamingException;
importjavax.naming.directory.Attributes;
importorg.springframework.ldap.core.AttributesMapper;
importorg.springframework.ldap.core.ContextMapper;
importorg.springframework.ldap.core.LdapTemplate;
importorg.springframework.ldap.core.DirContextAdapter;
importorg.springframework.ldap.core.support.DistinguishedName;
importorg.springframework.ldap.filter.AndFilter;
importorg.springframework.ldap.filter.EqualsFilter;
importorg.springframework.ldap.filter.WhitespaceWildcardsFilter;
publicclassPersonDaoImplimplementsPersonDao{
privateLdapTemplateldapTemplate;
publicvoidsetLdapTemplate(LdapTemplateldapTemplate){
this.ldapTemplate=ldapTemplate;
}
publicvoidcreate(Personperson){
DirContextAdaptercontext=newDirContextAdapter(buildDn(person));
mapToContext(person,context);
ldapTemplate.bind(context);
}
publicvoidupdate(Personperson){
Namedn=buildDn(person);
DirContextOperationscontext=ldapTemplate.lookupContext(dn);
mapToContext(person,context);
ldapTemplate.modifyAttributes(context);
}
publicvoiddelete(Personperson){
ldapTemplate.unbind(buildDn(person));
}
publicPersonfindByPrimaryKey(Stringname,Stringcompany,Stringcountry){
Namedn=buildDn(name,company,country);
return(Person)ldapTemplate.lookup(dn,getContextMapper());
}
publicListfindByName(Stringname){
AndFilterfilter=newAndFilter();
filter.and(newEqualsFilter("objectclass","person")).and(newWhitespaceWildcardsFilter("cn",name));
returnldapTemplate.search(DistinguishedName.EMPTY_PATH,filter.encode(),getContextMapper());
}
publicListfindAll(){
EqualsFilterfilter=newEqualsFilter("objectclass","person");
returnldapTemplate.search(DistinguishedName.EMPTY_PATH,filter.encode(),getContextMapper());
}
protectedContextMappergetContextMapper(){
returnnewPersonContextMapper();
}
protectedNamebuildDn(Personperson){
returnbuildDn(person.getFullname(),person.getCompany(),person.getCountry());
}
protectedNamebuildDn(Stringfullname,Stringcompany,Stringcountry){
DistinguishedNamedn=newDistinguishedName();
dn.add("c",country);
dn.add("ou",company);
dn.add("cn",fullname);
returndn;
}
protectedvoidmapToContext(Personperson,DirContextOperationscontext){
context.setAttributeValues("objectclass",newString[]{"top","person"});
context.setAttributeValue("cn",person.getFullName());
context.setAttributeValue("sn",person.getLastName());
context.setAttributeValue("description",person.getDescription());
}
privatestaticclassPersonContextMapperextendsAbstractContextMapper{
publicObjectdoMapFromContext(DirContextOperationscontext){
Personperson=newPerson();
person.setFullName(context.getStringAttribute("cn"));
person.setLastName(context.getStringAttribute("sn"));
person.setDescription(context.getStringAttribute("description"));
returnperson;
}
}
}
注意
在很多种情况下,唯一的DN用做构建对象时的重要属性,例如上面的代码中一个人的country,company 和fullname都用到DN,这就意味着你要在LdapTree中找到Entry,然后才能用rename()去更新属性值。如果你要保持不变的话,可以禁止用户修改属性或者rename()它