`
378629846
  • 浏览: 215676 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

LDAP查询分页,基于迭代器的查询分页

    博客分类:
  • java
阅读更多

      LDAP服务器端可以支持分页查询,但是有个前提条件,需要客户端先发送按关键字排序的指令后,才能执行分页查询。排序的过程是比较耗费时间的,需要对服务器做很多优化的操作。

      我的方法是在迭代结果集的时候实现分页,见代码:

 

package ldap.page;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;

/**
 * LDAP分页查询,使用时需要异步统计返回结果集的总行数
 * @author sxl
 *
 */
public class LdapSearch {
	/**
	 * 根据条件查找指定DN的条目下的一层所有属性
	 * 
	 * @param dn
	 *            要查询的BaseDN名称
	 * @param filter
	 *            要查询的过滤字符串
	 * @param returnedAtts
	 *            要查找的属性
	 * @param start
	 *            开始行
	 * @param limit
	 *            分页大小,如果为-1,则返回结果集的总行数
	 * @return 符合查询结果的List
	 */
	public static List searchContextOneByPage(String dn, String filter, String[] returnedAtts, int start, int limit){
		DirContext context = getDirContext("url","username","password");
		if(context == null) return null;
        // 实例化一个搜索器
 		SearchControls constraints = new SearchControls();
		// 设置搜索器的搜索范围为ONELEVEL
		constraints.setSearchScope( SearchControls.ONELEVEL_SCOPE);
		// 设置返回的属性
		if (returnedAtts != null) {
			constraints.setReturningAttributes(returnedAtts);
		}
		try {
			if (filter == null || filter.trim().equals("")) {
				filter = "objectclass=*";
			}
			NamingEnumeration<SearchResult> results = context.search(dn, filter, constraints);
			context.close();
			return searchPage(results,start,limit);
		} catch (NamingException ex) {
			ex.printStackTrace();
			return null;
		}
	}

	/**
	 * 分页查询
	 * @param resultList
	 * @param results
	 * @throws NamingException
	 */
	private static List searchPage(NamingEnumeration<SearchResult> results,int start,int limit) throws NamingException {
		List resultList = new ArrayList();
		int row = 0;
		boolean flag = false;
		while (results != null && results.hasMore()) {
			SearchResult si = results.next();// 取一个条目
			if(limit == -1)//如果limit==-1,只统计总行数
				row++;
			else {
				if(row++ == start) flag = true;//从start行开始取数据
				Attributes attrs = si.getAttributes();
				if (attrs != null && flag) {
					Map resultRowMap = new HashMap();// 一行数据
					for (NamingEnumeration ae = attrs.getAll(); ae.hasMoreElements();) {
						Attribute attr = (Attribute) ae.next();// 获取一个属性
						String attrId = attr.getID();
						Enumeration vals = attr.getAll();
						if (vals != null) {
							ArrayList valList = new ArrayList();
							while (vals.hasMoreElements()) {
								Object obj = vals.nextElement();
								if (obj instanceof String) {
									String _value = (String) obj;
									valList.add(_value);
								} else {
									valList.add(obj);
								}
							}
							resultRowMap.put(attrId, valList);
						}
					}
					resultList.add(resultRowMap);
					if(resultList.size() == limit){
						break;
					}
				}
			}
			
		}
		results.close();
		if(limit == -1)//如果limit为-1,则只返回总行数
			resultList.add(row);
		return resultList;
	}
	/**
	 * 从LDAP中取得一个连接
	 * @return DirContext
	 */
	private static DirContext getDirContext(String url,String userdn,String password){
		Properties mEnv = new Properties();
		mEnv.put(Context.AUTHORITATIVE, "true");
		mEnv.put("com.sun.jndi.ldap.connect.pool", "false");
		mEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		mEnv.put(Context.PROVIDER_URL, url);
		mEnv.put("com.sun.jndi.ldap.connect.timeout","3000");
		mEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
		mEnv.put(Context.SECURITY_PRINCIPAL, userdn);
		mEnv.put(Context.SECURITY_CREDENTIALS, password);
		DirContext ctx = null;
		try {
			ctx = new InitialLdapContext(mEnv, null);
		} catch (NamingException ex) {
			ex.printStackTrace();
			if(ctx != null)
				try {
					ctx.close();
				} catch (NamingException e) {
					e.printStackTrace();
				}
		}
		return ctx;

	}
}

 使用时,传递start和limit作为分页的参数,这样在迭代结果集的时候进行判断,从start开始一直取limit个元素结束。

但是,这里有一个前提条件,我们要异步来统计结果集的总行数,传递limit为-1。以EXT为例,我们覆盖Ext.PagingToolbar这个类里的一些函数,保存为myPagebar.js。

 

(function (){
	var total = 0;
	var T = Ext.Toolbar;
	Ext.PagingToolbar.prototype.setTotalCount = function(num){
		total = num;
	}
	Ext.PagingToolbar.prototype.getPageData = function(){
		if(total == 0){
			this.inputItem.setDisabled(true);
		}else{
			this.inputItem.setDisabled(false);
			this.last.setDisabled(false);
		}
		return {
		    total : total,
		    activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
		    pages : Math.ceil(total/this.pageSize)
		};
	}
	Ext.PagingToolbar.prototype.onLoad = function(store, r, o){
	    if(!this.rendered){
	        this.dsLoaded = [store, r, o];
	        return;
	    }
	    var p = this.getParams();
	    this.cursor = (o.params && o.params[p.start]) ? o.params[p.start] : 0;
	    var d = this.getPageData(), ap = d.activePage, ps = d.pages;
	
	    this.afterTextItem.setText(String.format(this.afterPageText, d.pages));
	    this.inputItem.setValue(ap);
	    this.first.setDisabled(ap == 1);
	    this.prev.setDisabled(ap == 1);
	    this.next.setDisabled(ap == ps);
	    //this.last.setDisabled(ap == ps);
	    this.refresh.enable();
	    this.updateInfo();
	    this.fireEvent('change', this, d);
	}
	Ext.PagingToolbar.prototype.updateInfo = function(){ 
		if(this.displayItem){
	        var count = this.store.getCount();
	        var msg = count == 0 ?
	            this.emptyMsg :
	            String.format(
	                this.displayMsg,
	                this.cursor+1, this.cursor+count, total
	            );
	        this.displayItem.setText(msg);
	    }
	}
	Ext.PagingToolbar.prototype.changePage = function(page){
	    this.doLoad(((page-1) * this.pageSize).constrain(0, total));
	}
	Ext.PagingToolbar.prototype.moveLast = function(){
	    var extra = total % this.pageSize;
	    this.doLoad(extra ? (total - extra) : total - this.pageSize);
	}
})();

 在jsp里引入myPagebar.js后,按照正常的方式使用Ext.PagingToolbar就可以了。

这样,在使用Ext.grid.GridPanel来显示数据之前,先使用Ajax去后台统计总行数,传递参数里增加start:1,limit:-1。

在Ajax成功返回后,调用Ext.PagingToolbar.prototype.setTotalCount(totalRow);同时,Ext.grid.GridPanel的store会去后台load数据,传给后台的参数包括start:1,limit:50,表示取第一页的50行数据。这样就实现了后台分页的效果。

     如果数据很多,统计总行数会耗时较长,这时Ext.grid.GridPanel上显示的总页数为0,但是可以点击<下一页>,继续访问下一页的数据。直到总行数统计完成后,才能看到总页数,才能翻到最后一页。

     这种方式避免了数据过多时的内存溢出问题,也提高了数据的访问速度,最起码是页数比较靠前的数据的访问速度。友好度也要好很多。

分享到:
评论
2 楼 softfn 2014-01-15  
没解决本质问题 你这个只是为了页面分页而已
1 楼 tangmin823 2013-02-19  
这个根本算不上LDAP分页查询啊,不也是先查询出所有的记录吗?!

相关推荐

    Ldap 分页问题

    标题中的“Ldap 分页问题”指的是在...总的来说,理解和正确实施LDAP分页对于优化大型目录服务的查询性能至关重要。开发者需要熟悉相关控制项,理解服务器的限制,并能够适当地调整查询策略以适应不同的环境和需求。

    Spring LDAP API(Spring LDAP 开发文档).CHM

    Spring LDAP。 官网 Spring LDAP API。 Spring LDAP 开发文档。

    基于关系数据库的LDAP证书查询服务器的实现

    ### 基于关系数据库的LDAP证书查询服务器的实现 #### 概述 随着网络通信技术的迅速发展,网络安全已成为互联网应用中不可忽视的关键因素。公钥基础设施(Public Key Infrastructure, PKI)作为保障网络通信安全的...

    ldap域信息查询工具.zip

    总结来说,"ldap域信息查询工具.zip"包含了一个关于如何使用LDP工具进行LDAP查询的文档和实际的LDP执行程序。通过这个工具,IT管理员可以高效地管理他们的LDAP目录,包括查询信息、调试问题和更新数据,这对于维护...

    RuoYi前后端不分离项目整合LDAP

    基于RuoYi框架,使用的是ruoyi前后端不分离的版本,实现对LDAP的整合 基于RuoYi框架,使用的是ruoyi前后端不分离的版本,实现对LDAP的整合 基于RuoYi框架,使用的是ruoyi前后端不分离的版本,实现对LDAP的整合 基于...

    LDAP 查询指定目录-所有活动用户

    LDAP是一种基于X.500标准的子集,用于查询、浏览和修改目录服务中的信息。它提供了一种高效、灵活的方式来存储和检索大量的组织数据,如员工信息、资源分配等。本文将深入探讨如何通过LDAP查询指定目录中的所有活动...

    Google Doc:常用LDAP查询

    理解并熟练掌握这些查询语句对于管理和维护基于LDAP的企业级系统至关重要。 此外,需要注意的是,虽然本文提供了多种查询方式,但在实际应用中还需要根据具体的LDAP服务器类型(如Active Directory、OpenLDAP等)...

    Novell.Directory.Ldap.dll

    Novell.Directory.Ldap.dll是C#编程中用于访问Directory(目录服务)或eDirectory(Novell的企业级目录服务)的重要组件,它提供了一组丰富的类和方法,使得开发者能够方便地进行目录操作,如查询、添加、删除和修改...

    AD域分页查询全部域用户数据

    因此,"AD域分页查询全部域用户数据"是一种优化查询效率的方法,它允许管理员分批获取用户信息,而不是一次性加载。 首先,我们需要理解AD域分页查询的工作原理。在Java中,我们可以使用JNDI(Java Naming and ...

    LDAP编辑器:可以连接LDAP和编辑LDAP数据

    **LDAP编辑器:连接与编辑LDAP数据** LDAP(Lightweight Directory Access Protocol)是一种轻量级目录访问协议,常用于组织和管理分布式身份信息。它提供了一种标准的方式来存储和检索用户、组、服务等对象的数据...

    RFC2254LDAP查询过滤器的字符串表示法中文版

    这些过滤器基于属性和值的比较,允许用户根据需要查找满足特定条件的对象。例如,可以查找所有名字为“张三”的用户或者所有状态为“激活”的账户。 **2. RFC2254字符串表示法** RFC2254规定了一种特殊的编码规则,...

    基于LDAP的XML数据访问

    当从LDAP数据库中检索到需要的数据后,这些数据又通过LDAP查询处理器返回给XML对象设计器,最终转换为查询者可理解的XML格式。 在实际应用中,LDAP通常用于存储和管理企业级的目录信息,如用户认证信息、用户组信息...

    RFC2254LDAP查询过滤器的字符串表示法

    LDAP RFC2254LDAP查询过滤器的字符串表示法,中文版。 LDAPChina经典原创。

    对LDAP的基本操作(Spring-ldap)+Ext实现显示LDAP的树状结构

    rar包:一个Web工程, 主要有,利用Spring-ldap对LDAP的基本操作(查询,增删改);Extjs实现的对Ldap的树状结构的显示,结构有点类似Softerra LDAP;一个测试类。 pdf:spring-ldap-reference.pdf Extjs.pdf ...

    用sql语句的方式操作ldap

    这通常涉及将SQL语句转换为LDAP过滤器,例如,"SELECT * FROM ou=People WHERE uid=john" 可能会转换为 LDAP 过滤器 "(&(objectClass=person)(uid=john))"。 **三、JSP/Servlet操作LDAP** 在Java环境中,我们可以...

    ldap:GO编程语言的基本LDAP v3功能

    该库实现以下规范: 用于基本操作进行密码修改操作解析专有名称特征: 连接到LDAP服务器(非TLS,TLS,STARTTLS) 绑定到LDAP服务器搜索条目过滤器编译/反编译分页搜索结果修改请求/响应添加请求/响应删除请求/响应...

    基于SSL的ldap安全访问AD认证

    基于SSL的LDAP安全访问AD认证 基于SSL的LDAP安全访问AD认证是指使用SSL(Secure Sockets Layer)协议来保护LDAP(Lightweight Directory Access Protocol)协议与AD(Active Directory)的通信,使得密码在网络中...

    基于web的LDAP浏览器(Web LDAP Browser)

    基于Web的LDAP浏览器是一种用户友好的工具,它允许用户通过Web界面来查询、浏览和管理 Lightweight Directory Access Protocol (LDAP) 服务器的数据。这种B/S架构的应用程序通常由HTML、DHTML、Java以及LDAP等相关...

    基于LDAP统一用户管理系统的研究与应用

    《基于LDAP统一用户管理系统的研究与应用》 在信息化时代的今天,用户管理是企业信息系统的核心环节。随着企业IT架构的日益复杂,多应用系统的并存使得用户管理变得愈发困难。为了解决这一问题,基于LDAP...

Global site tag (gtag.js) - Google Analytics