读使用JNDI访问Domino目录之后
- 创建一个JNDI可用连接的过程
- 创建一个HashTable,存入LDAP工厂类(Context.INITIAL_CONTEXT_FACTORY)、服务器地址(Context.PROVIDER_URL)、(如果需要验证的话)验证方式(Context.SECURITY_AUTHENTICATION)、用户账号(Context.SECURITY_PRINCEPAL)、用户证书(Context.SECURITY_CREDENTIALS)
- 创建一个context对象(DirContext ctx = new InitialDirContext(env))
- 调用该Context对象的查询、插入、删除等操作的方法
读JNDI访问LDAP目录服务之后
- JNDI所有异常都继承于NamingException
- 认证失败抛出AuthenticationException
- DirContext.lookup(“cn=…,ou=…”)可以获取单个对象,通过cast可以实现对对象的转换
列举上下文的方法DirContext.list(“ou=…”)和DirContext.listBindings(“ou=…”)
- DirContext.list(“ou=…”)枚举所有NameClassPair(对象名:对象类型名)
NamingEnumeration list = ctx.list("ou=..."); while(list.hasMore()){ NameClassPair nc = (NameClassPair)list.next(); System.out.println(nc); }
- DirContext.listBindings(“ou=…”)不仅枚举NameClassPair还包括了对象(对象名:对象类型名@对象)
NamingEnumeration bindings = ctx.listBindings("ou=..."); while(bindings.hasMore()){ Binding bd = (Binding)bindings.next(); System.out.println(bd.getName() + ":" + bd.getObject()); }
- namingEnumeration的终止通过三种形式,一般、显式、非显式
- 正常的调用namingEnumeration,当hasMore正常的返回false时,NamingEnumeration终止
- 在枚举过程中使用close()强行终止
- 在枚举过程中抛出异常终止
对对象进行绑定通过bind()方法实现
Fruit fruit = new Fruit("orange"); ctx.bind("cn=Favorite Fruit", fruit);
通过上述例子能够把Fruit对象绑定到Favorite Fruit的对象名中,假如当前对象名已经绑定则会抛出NameAlreadyBoundException,应当用rebind()方法对上一对象解绑并重新绑定新的对象
通过unbind()可以解除对一个对象的绑定
ctx.unbind("cn=Favorite Fruit")
重命名rename()
ctx.rename("cn=old name", "cn=new name")
创建ctx的子上下文
Attributes atts = new BasicAttributes(true);//忽略大小写 Attribute objclass = new BasicAttribute("objectclass"); objclass.add("top"); objclass.add("organizationalUnit"); attrs.put(objclass); Context subctx = ctx.createSubcontext("NewOu", attrs);//创建ou=NewOu的上下文
- 销毁上下文,ctx.destorySubcontext(“NewOu”)
读取属性
Attributes answer = ctx.getAttributes("cn...,ou=...");//获取某个对象的Attrs对象 for(NamingEnumeration ae = answer.getAll();ae.hasMore();){ Attribute attr = (Attribute)ae.next(); System.out.println("attribute:" + attr.getID()); for(NamingEnumeration e = attr.getAll();attr.hasMore();){ System.out.println("value:" + e.next()); } }
返回选中的属性,通过数组指定返回什么属性
String[] attrIDs = {"an", "telephonenumber"}; Attributes answer = ctx.getAttributes("cn=...,ou=...", attrIDs);
修改列表的方式之一是通过ModificationItem对象实现的,它定义了三种修改方法
- ADD_ATTRIBUTE
- REPLACE_ATTIRBUTE
- REMOVE_ATTRIBUTE
ModificationItem[] mods = new ModificationItem[3]; mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("mail", "979831398@qq.com")); mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("telephonenumber", "5555555")); mods[2] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("jpegphoto")) ctx.modifyAttributes(name, mods);
ps:在为telephone中增加新值时要注意telephonenumber的约束,是否允许存在多值,这些约束应该被定义在scheme文件中。
- DirContext.bind()可以添加有属性的绑定,通过ctx.bind(“ou=favorite,ou=Fruits”, fruit, attrs)
- 同样的,通过rebind可以替换有属性的绑定
JNDI对搜索的支持提供了三种搜索方式,分别是基本搜索、搜索过滤器、搜索控制
基本搜索
Attributes matchAttrs = new BasicAttributes(true); matchAttrs.put(new BasicAttribute("sn", "GGG"));//指定必须含有sn属性,其值必须是GGG matchAttrs.put(new BasicAttribute("mail"));//指定必须含有mail属性,其值任意 NamingEnumeration answer = ctx.search("ou=People", matchAttrs);//指定在ou=People中查询数据 返回基本搜索中选中的属性同样可以通过attriIDs指定 String[] attrIDs = {"sn", "telephonenumber", "sex"} NamingEnumeration answer = ctx.search("ou=People", matchAttrs, attrIDs);
搜索过滤器
搜索过滤器支持搜索语法,它同样适用search方法,但是它要求指定一个搜索控制器和对应的搜索字符串
SearchControls ctls = new SearchControls() String filter = "(&(sn=GGG)(mail=*))";//改过滤器与上文等价 NamingEnumeration answer = ctx.search("ou=People", filter, ctls);
- 搜索过滤器语法
& 仅当条目对于&所在域内所有项为true时获取该条目 | 当条目对于|所在区域内任意项为true时获取该条目 ! 对条件求反 = 指定属性值必须为某一确定值时 ~= 近似等于 >= 大于 <= 小于 =* 存在某属性时返回条目 * 通配符,如L*匹配LP、LD等 \ 转义字符
搜索过滤器用括号区分所在区域
- 返回选中属性同样通过attrIDs指定,不过它被设置在搜索过滤器中
String[] attrIDs = {"sn", "telephonenumber"};
SearchControls ctls = new SearchControls();
ctls.setReturningAttributes(attrIDs);
- 通过SearchControls.setSearchScope()指定SearchControls的范围
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);//指定整棵子树范围
NamingEnumeration answer = ctx.search("", filter, ctls);
也可以搜索命名对象,通过指定scope为SearchControls.OBJECT_SCOPE
- 可以限制返回的结果集数量,通过SearchControls.setCountLimit(num);
- 可以限制应答时间,通过SearchControls.setTimeLimit(n ms)指定应答时间,当应答时间结束,结束搜索。
- 异常处理
LDAP服务器向其他工具应答(例如管理控制台)但不应答您程序的请求。
原因:服务器没有应答LDAP v3的连接全逆光球。一些服务器(尤其是公共服务器)不能正确的应答LDAP v3,使用忽略的方式代替拒绝。同时,一些LDAP v3服务器有错误处理机制,Sun的LDAP服务提供者自动发送并且通常返回特定服务器错误码。
解决方案:尝试设置环境参数“java.naming.ldap.version”为“2”。LDAP服务提供者默认尝试使用LDAP v3连接LDAP服务器,然后使用LDAP v2。如果服务器静默忽略v3的请求,那么提供者假设请求生效了。使用这种服务器,您必须显式的设置协议版本,确保服务器有正确的行为。
如果服务器是v3服务器,那么尝试在创建初始化上下文之前设置这些环境参数:env.put(Context.REFERRAL, “throw”);
这样关闭了LDAP提供者自动发送的控制